diff --git a/lib/arpaka/generator.rb b/lib/arpaka/generator.rb index 1404d66..e9c6a50 100644 --- a/lib/arpaka/generator.rb +++ b/lib/arpaka/generator.rb @@ -34,7 +34,7 @@ def generate(ruby_source: nil, parse_y: nil, class_name:) end source = "# frozen_string_literal: true\n" \ "# Generated by Arpaka #{Lrama::Ruby::VERSION}. Do not edit.\n" \ - "# Ruby source profile: #{ruby_source ? RubyGrammar::REVISION : 'parse.y only'}\n" \ + "# Ruby source profile: #{ruby_source ? artifacts.fetch('source_profile') : 'parse.y only'}\n" \ "# parse.y SHA256: #{Digest::SHA256.file(grammar_filename).hexdigest}\n" \ "#{notices.join("\n").lines.map { |line| "# #{line}" }.join}\n" \ "class #{class_name}\n#{parser}\n#{runtime}\nend\n" diff --git a/lib/arpaka/profile/ruby.rb b/lib/arpaka/profile/ruby.rb index c42d476..d05630e 100644 --- a/lib/arpaka/profile/ruby.rb +++ b/lib/arpaka/profile/ruby.rb @@ -15,24 +15,34 @@ module RUBY def self.select(grammar) if grammar.rules.any? { |rule| rule.lhs.id.s_value == "value_expr_command" } CURRENT - elsif grammar.rules.any? { |rule| rule.lhs.id.s_value == "top_compstmt" } + elsif grammar.rules.any? { |rule| rule.lhs.id.s_value == "top_compstmt" && + rule.rhs.any? { |symbol| symbol.id.s_value == "option_terms" } } legacy + elsif grammar.rules.any? { |rule| rule.lhs.id.s_value == "top_compstmt" && + rule.rhs.any? { |symbol| symbol.id.s_value == "opt_terms" } } + legacy_3_3 else raise ::Arpaka::Error, "Unsupported Ruby parse.y profile" end end def self.legacy - @legacy ||= begin - box = ::Ruby::Box.new - profile = box.eval(File.read(File.join(__dir__, "ruby_3_4.rb"))) - unless profile.is_a?(Hash) && profile["name"] == "ruby-3.4" - raise ::Arpaka::Error, "Invalid Ruby 3.4 profile" - end - profile.freeze - rescue SyntaxError, TypeError => error - raise ::Arpaka::Error, "Ruby legacy profile loading failed: #{error.message}" + @legacy ||= load("ruby_3_4.rb", "ruby-3.4") + end + + def self.legacy_3_3 + @legacy_3_3 ||= load("ruby_3_3.rb", "ruby-3.3") + end + + def self.load(filename, name) + box = ::Ruby::Box.new + profile = box.eval(File.read(File.join(__dir__, filename))) + unless profile.is_a?(Hash) && profile["name"] == name + raise ::Arpaka::Error, "Invalid #{name} profile" end + profile.freeze + rescue SyntaxError, TypeError => error + raise ::Arpaka::Error, "Ruby profile loading failed: #{error.message}" end end end diff --git a/lib/arpaka/profile/ruby_3_3.rb b/lib/arpaka/profile/ruby_3_3.rb new file mode 100644 index 0000000..2869c75 --- /dev/null +++ b/lib/arpaka/profile/ruby_3_3.rb @@ -0,0 +1,800 @@ +# frozen_string_literal: true + +# Ruby 3.3.10 (v3_3_10) profile. Rule IDs are local to this grammar. +{ + "name" => "ruby-3.3", + "source_tag" => "v3_3_10", + "source_revision" => "343ea050023cfc0374fdea6fdf625b2f57b716a4", + "source_sha256" => "0347b145280f89b0052aaaa506aa2022c9abdfa2c37677203d53a1a2b3e35861", + "runtime" => { + "ast_nodes" => %w[assignment singleton_method singleton_class pattern].freeze, + "builder_methods" => %w[assignment singleton_method singleton_class rescue].freeze, + "lexer" => {"source_text_tokens" => ["tOP_ASGN"].freeze}.freeze + }.freeze, + "actions" => { + 1 => ["ported", "nil"], + 2 => ["ported", "@builder.program($2)"], + 3 => ["ported", "@builder.body_nodes($1)"], + 4 => ["ported", "[].freeze"], + 5 => ["ported", "[$1].freeze"], + 6 => ["ported", "($1 + [$3]).freeze"], + 7 => ["ported", "$1"], + 8 => ["ported", "$2"], + 9 => ["ported", "nil"], + 10 => ["ported", "@builder.begin_block($2)"], + 11 => ["ported", "nil"], + 12 => ["ported", "nil"], + 13 => ["ported", "@builder.body_statement($1, $3, $6, $8)"], + 14 => ["ported", "nil"], + 15 => ["ported", "@builder.body_statement($1, $3, nil, $5)"], + 16 => ["ported", "@builder.body_nodes($1)"], + 17 => ["ported", "[].freeze"], + 18 => ["ported", "[$1].freeze"], + 19 => ["ported", "($1 + [$3]).freeze"], + 20 => ["ported", "$1"], + 21 => ["ported", "nil"], + 22 => ["ported", "$3"], + 23 => ["ported", "nil"], + 24 => ["ported", "$1"], + 25 => ["ported", "nil"], + 26 => ["ported", "@builder.alias_node($2, $4)"], + 27 => ["ported", "@builder.alias_node($2, $3)"], + 28 => ["ported", "@builder.alias_node($2, $3)"], + 29 => ["unsupported", "@builder.unsupported(31)"], + 30 => ["ported", "@builder.undef_node($2)"], + 31 => ["ported", "@builder.if_node($3, [$1], nil)"], + 32 => ["ported", "@builder.unless_node($3, [$1], nil)"], + 33 => ["ported", "@builder.loop(:while, $3, [$1])"], + 34 => ["ported", "@builder.loop(:until, $3, [$1])"], + 35 => ["ported", "@builder.rescue_modifier($1, $4)"], + 36 => ["ported", "@builder.end_block($4)"], + 37 => ["ported", "$1"], + 38 => ["ported", "@builder.multiple_assign($1, $4)"], + 39 => ["ported", "@builder.assignment($1, $4)"], + 40 => ["ported", "@builder.multiple_assign($1, @builder.rescue_modifier($4, $7))"], + 41 => ["ported", "@builder.multiple_assign($1, $4)"], + 42 => ["ported", "$1"], + 43 => ["ported", "nil"], + 44 => ["ported", "@builder.assignment($1, $4)"], + 45 => ["ported", "@builder.opassign($1, $2, $4)"], + 46 => ["ported", "@builder.opassign(@builder.index($1, $3 || []), $5, $7)"], + 47 => ["ported", "@builder.opassign(@builder.field($1, $2, $3), $4, $6)"], + 48 => ["ported", "@builder.opassign(@builder.field($1, $2, $3), $4, $6)"], + 49 => ["ported", "@builder.opassign(@builder.field($1, :\"::\", $3), $4, $6)"], + 50 => ["ported", "@builder.opassign(@builder.field($1, $2, $3), $4, $6)"], + 51 => ["ported", "@builder.def_node($1, $2, $4)"], + 52 => ["ported", "@builder.singleton_method_node($1[0], $1[2], $2, $4)"], + 53 => ["unsupported", "@builder.unsupported(56)"], + 54 => ["ported", "$1"], + 55 => ["ported", "@builder.rescue_modifier($1, $4)"], + 56 => ["ported", "@builder.unary(\":!\", $3)"], + 57 => ["ported", "$1"], + 58 => ["ported", "@builder.rescue_modifier($1, $4)"], + 59 => ["ported", "$1"], + 60 => ["ported", "$1"], + 61 => ["ported", "@builder.binary(:and, $1, $3)"], + 62 => ["ported", "@builder.binary(:or, $1, $3)"], + 63 => ["ported", "@builder.unary(\":!\", $3)"], + 64 => ["ported", "@builder.unary(:\"!\", $2)"], + 65 => ["ported", "nil"], + 66 => ["ported", "@builder.case_node($1, [@builder.when_node($7, [])], nil)"], + 67 => ["ported", "nil"], + 68 => ["ported", "@builder.case_node($1, [@builder.when_node($7, [])], nil)"], + 69 => ["ported", "$1"], + 70 => ["ported", "$1"], + 71 => ["ported", "$2"], + 72 => ["ported", "nil"], + 73 => ["ported", "[$2, $3, $5].freeze"], + 74 => ["ported", "$1"], + 75 => ["ported", "nil"], + 76 => ["ported", "nil"], + 77 => ["ported", "nil"], + 78 => ["ported", "$2"], + 79 => ["ported", "$1"], + 80 => ["ported", "$1"], + 81 => ["ported", "$1"], + 82 => ["ported", "@builder.receiver_call($1, $2, $3, $4)"], + 83 => ["ported", "$2"], + 84 => ["ported", "$1"], + 85 => ["ported", "@builder.call($1, $2 || [])"], + 86 => ["ported", "@builder.block_call(@builder.call($1, $2 || []), $3)"], + 87 => ["ported", "@builder.receiver_call($1, $2, $3, $4)"], + 88 => ["ported", "@builder.block_call(@builder.receiver_call($1, $2, $3, $4), $5)"], + 89 => ["ported", "@builder.receiver_call($1, :\"::\", $3, $4)"], + 90 => ["ported", "@builder.block_call(@builder.receiver_call($1, :\"::\", $3, $4), $5)"], + 91 => ["ported", "@builder.block_call(@builder.receiver_call($1, :\"::\", $3, []), $5)"], + 92 => ["ported", "@builder.call(:super, $2 || [])"], + 93 => ["ported", "@builder.call(:yield, $2 || [])"], + 94 => ["ported", "@builder.call(:return, $2 || [])"], + 95 => ["ported", "@builder.call(:break, $2 || [])"], + 96 => ["ported", "@builder.call(:next, $2 || [])"], + 97 => ["ported", "$1"], + 98 => ["ported", "$2"], + 99 => ["ported", "$1"], + 100 => ["ported", "$2"], + 101 => ["ported", "$1"], + 102 => ["ported", "(Array($1) + [$2]).freeze"], + 103 => ["ported", "(Array($1) + [$3]).freeze"], + 104 => ["ported", "$1"], + 105 => ["ported", "$1"], + 106 => ["ported", "$1"], + 107 => ["ported", "$2"], + 108 => ["ported", "$2"], + 109 => ["ported", "nil"], + 110 => ["ported", "$2"], + 111 => ["ported", "$1"], + 112 => ["ported", "$2"], + 113 => ["ported", "[$1].freeze"], + 114 => ["ported", "($1 + [$2]).freeze"], + 115 => ["ported", "$1"], + 116 => ["ported", "$1"], + 117 => ["ported", "$1"], + 118 => ["ported", "$1"], + 119 => ["ported", "@builder.index($1, $3 || [])"], + 120 => ["ported", "$1"], + 121 => ["ported", "$1"], + 122 => ["ported", "$1"], + 123 => ["ported", "@builder.variable(:constant, $3)"], + 124 => ["ported", "@builder.variable(:constant, $2)"], + 125 => ["ported", "$1"], + 126 => ["ported", "@builder.declare_local($1)"], + 127 => ["ported", "$1"], + 128 => ["ported", "@builder.index($1, $3 || [])"], + 129 => ["ported", "@builder.field($1, $2, $3)"], + 130 => ["ported", "@builder.field($1, $2, $3)"], + 131 => ["ported", "@builder.field($1, $2, $3)"], + 132 => ["ported", "@builder.field($1, :\"::\", $3)"], + 133 => ["ported", "@builder.variable(:constant, $2)"], + 134 => ["ported", "$1"], + 135 => ["ported", "$1"], + 136 => ["ported", "$1"], + 137 => ["ported", "$2"], + 138 => ["ported", "$1"], + 139 => ["ported", "$3"], + 140 => ["ported", "$1"], + 141 => ["ported", "$1"], + 142 => ["ported", "$1"], + 143 => ["ported", "$1"], + 144 => ["ported", "$1"], + 145 => ["ported", "$1"], + 146 => ["ported", "$1"], + 147 => ["ported", "[$1].freeze"], + 148 => ["ported", "nil"], + 149 => ["ported", "($1 + [$4]).freeze"], + 150 => ["ported", "@builder.operator(\"|\")"], + 151 => ["ported", "@builder.operator(\"^\")"], + 152 => ["ported", "@builder.operator(\"&\")"], + 153 => ["ported", "@builder.operator(\"<=>\")"], + 154 => ["ported", "@builder.operator(\"==\")"], + 155 => ["ported", "@builder.operator(\"===\")"], + 156 => ["ported", "@builder.operator(\"=~\")"], + 157 => ["ported", "@builder.operator(\"!~\")"], + 158 => ["ported", "@builder.operator(\">\")"], + 159 => ["ported", "@builder.operator(\">=\")"], + 160 => ["ported", "@builder.operator(\"<\")"], + 161 => ["ported", "@builder.operator(\"<=\")"], + 162 => ["ported", "@builder.operator(\"!=\")"], + 163 => ["ported", "@builder.operator(\"<<\")"], + 164 => ["ported", "@builder.operator(\">>\")"], + 165 => ["ported", "@builder.operator(\"+\")"], + 166 => ["ported", "@builder.operator(\"-\")"], + 167 => ["ported", "@builder.operator(\"*\")"], + 168 => ["ported", "@builder.operator(\"*\")"], + 169 => ["ported", "@builder.operator(\"/\")"], + 170 => ["ported", "@builder.operator(\"%\")"], + 171 => ["ported", "@builder.operator(\"**\")"], + 172 => ["ported", "@builder.operator(\"**\")"], + 173 => ["ported", "@builder.operator(\"!\")"], + 174 => ["ported", "@builder.operator(\"~\")"], + 175 => ["ported", "@builder.operator(\"+@\")"], + 176 => ["ported", "@builder.operator(\"-@\")"], + 177 => ["ported", "@builder.operator(\"[]\")"], + 178 => ["ported", "@builder.operator(\"[]=\")"], + 179 => ["ported", "@builder.operator(\"`\")"], + 180 => ["ported", "@builder.reserved_word(\"__LINE__\")"], + 181 => ["ported", "@builder.reserved_word(\"__FILE__\")"], + 182 => ["ported", "@builder.reserved_word(\"__ENCODING__\")"], + 183 => ["ported", "@builder.reserved_word(\"BEGIN\")"], + 184 => ["ported", "@builder.reserved_word(\"END\")"], + 185 => ["ported", "@builder.reserved_word(\"alias\")"], + 186 => ["ported", "@builder.reserved_word(\"and\")"], + 187 => ["ported", "@builder.reserved_word(\"begin\")"], + 188 => ["ported", "@builder.reserved_word(\"break\")"], + 189 => ["ported", "@builder.reserved_word(\"case\")"], + 190 => ["ported", "@builder.reserved_word(\"class\")"], + 191 => ["ported", "@builder.reserved_word(\"def\")"], + 192 => ["ported", "@builder.reserved_word(\"defined?\")"], + 193 => ["ported", "@builder.reserved_word(\"do\")"], + 194 => ["ported", "@builder.reserved_word(\"else\")"], + 195 => ["ported", "@builder.reserved_word(\"elsif\")"], + 196 => ["ported", "@builder.reserved_word(\"end\")"], + 197 => ["ported", "@builder.reserved_word(\"ensure\")"], + 198 => ["ported", "@builder.reserved_word(\"false\")"], + 199 => ["ported", "@builder.reserved_word(\"for\")"], + 200 => ["ported", "@builder.reserved_word(\"in\")"], + 201 => ["ported", "@builder.reserved_word(\"module\")"], + 202 => ["ported", "@builder.reserved_word(\"next\")"], + 203 => ["ported", "@builder.reserved_word(\"nil\")"], + 204 => ["ported", "@builder.reserved_word(\"not\")"], + 205 => ["ported", "@builder.reserved_word(\"or\")"], + 206 => ["ported", "@builder.reserved_word(\"redo\")"], + 207 => ["ported", "@builder.reserved_word(\"rescue\")"], + 208 => ["ported", "@builder.reserved_word(\"retry\")"], + 209 => ["ported", "@builder.reserved_word(\"return\")"], + 210 => ["ported", "@builder.reserved_word(\"self\")"], + 211 => ["ported", "@builder.reserved_word(\"super\")"], + 212 => ["ported", "@builder.reserved_word(\"then\")"], + 213 => ["ported", "@builder.reserved_word(\"true\")"], + 214 => ["ported", "@builder.reserved_word(\"undef\")"], + 215 => ["ported", "@builder.reserved_word(\"when\")"], + 216 => ["ported", "@builder.reserved_word(\"yield\")"], + 217 => ["ported", "@builder.reserved_word(\"if\")"], + 218 => ["ported", "@builder.reserved_word(\"unless\")"], + 219 => ["ported", "@builder.reserved_word(\"while\")"], + 220 => ["ported", "@builder.reserved_word(\"until\")"], + 221 => ["ported", "@builder.assignment($1, $4)"], + 222 => ["ported", "@builder.opassign($1, $2, $4)"], + 223 => ["ported", "@builder.opassign(@builder.index($1, $3 || []), $5, $7)"], + 224 => ["ported", "@builder.opassign(@builder.field($1, $2, $3), $4, $6)"], + 225 => ["ported", "@builder.opassign(@builder.field($1, $2, $3), $4, $6)"], + 226 => ["ported", "@builder.opassign(@builder.field($1, $2, $3), $4, $6)"], + 227 => ["ported", "@builder.opassign(@builder.field($1, :\"::\", $3), $4, $6)"], + 228 => ["ported", "@builder.opassign(@builder.field(nil, :\"::\", $2), $3, $5)"], + 229 => ["unsupported", "@builder.unsupported(234)"], + 230 => ["ported", "@builder.range(:\"..\", $1, $3)"], + 231 => ["ported", "@builder.range(:\"...\", $1, $3)"], + 232 => ["ported", "@builder.range(:\"..\", $1, nil)"], + 233 => ["ported", "@builder.range(:\"...\", $1, nil)"], + 234 => ["ported", "@builder.range(:\"..\", nil, $2)"], + 235 => ["ported", "@builder.range(:\"...\", nil, $2)"], + 236 => ["ported", "@builder.binary(:+, $1, $3)"], + 237 => ["ported", "@builder.binary(:-, $1, $3)"], + 238 => ["ported", "@builder.binary(:*, $1, $3)"], + 239 => ["ported", "@builder.binary(:/, $1, $3)"], + 240 => ["ported", "@builder.binary(:%, $1, $3)"], + 241 => ["ported", "@builder.binary(:\"**\", $1, $3)"], + 242 => ["ported", "@builder.binary(:\"**\", @builder.unary(:-@, $2), $4)"], + 243 => ["ported", "@builder.unary(:+, $2)"], + 244 => ["ported", "@builder.unary(:-, $2)"], + 245 => ["ported", "@builder.binary(:\"|\", $1, $3)"], + 246 => ["ported", "@builder.binary(:\"^\", $1, $3)"], + 247 => ["ported", "@builder.binary(:\"&\", $1, $3)"], + 248 => ["ported", "@builder.binary(:\"<=>\", $1, $3)"], + 249 => ["ported", "$1"], + 250 => ["ported", "@builder.binary(:\"==\", $1, $3)"], + 251 => ["ported", "@builder.binary(:\"===\", $1, $3)"], + 252 => ["ported", "@builder.binary(:\"!=\", $1, $3)"], + 253 => ["ported", "@builder.binary(:\"=~\", $1, $3)"], + 254 => ["ported", "@builder.binary(:\"!~\", $1, $3)"], + 255 => ["ported", "@builder.unary(:\"!\", $2)"], + 256 => ["ported", "@builder.unary(:\"~\", $2)"], + 257 => ["ported", "@builder.binary(:\"<<\", $1, $3)"], + 258 => ["ported", "@builder.binary(:\">>\", $1, $3)"], + 259 => ["ported", "@builder.binary(:\"&&\", $1, $3)"], + 260 => ["ported", "@builder.binary(:\"||\", $1, $3)"], + 261 => ["ported", "@builder.call(:defined, [$4])"], + 262 => ["ported", "@builder.ternary($1, $3, $6)"], + 263 => ["ported", "@builder.def_node($1, $2, $4)"], + 264 => ["ported", "@builder.singleton_method_node($1[0], $1[2], $2, $4)"], + 265 => ["ported", "$1"], + 266 => ["ported", "$1"], + 267 => ["ported", "@builder.rescue_modifier($1, $4)"], + 268 => ["ported", "@builder.unary(\":!\", $3)"], + 269 => ["ported", "@builder.operator(\">\")"], + 270 => ["ported", "@builder.operator(\"<\")"], + 271 => ["ported", "@builder.operator(\">=\")"], + 272 => ["ported", "@builder.operator(\"<=\")"], + 273 => ["ported", "@builder.binary($2, $1, $3)"], + 274 => ["ported", "@builder.binary($2, $1, $3)"], + 275 => ["ported", "nil"], + 276 => ["ported", "nil"], + 277 => ["ported", "nil"], + 278 => ["ported", "$1"], + 279 => ["ported", "[].freeze"], + 280 => ["ported", "$1"], + 281 => ["ported", "($1 + $3).freeze"], + 282 => ["ported", "$1"], + 283 => ["ported", "$1"], + 284 => ["ported", "@builder.rescue_modifier($1, $4)"], + 285 => ["ported", "$2"], + 286 => ["ported", "($2 + [$4]).freeze"], + 287 => ["ported", "$2"], + 288 => ["ported", "nil"], + 289 => ["ported", "$1"], + 290 => ["ported", "nil"], + 291 => ["ported", "$1"], + 292 => ["ported", "$1"], + 293 => ["ported", "$1"], + 294 => ["ported", "$1"], + 295 => ["ported", "[$1].freeze"], + 296 => ["ported", "$1"], + 297 => ["ported", "$1"], + 298 => ["ported", "(($1 || []) + ($3 || [])).freeze"], + 299 => ["ported", "$1"], + 300 => ["ported", "nil"], + 301 => ["ported", "$2"], + 302 => ["ported", "$2"], + 303 => ["ported", "nil"], + 304 => ["ported", "$2"], + 305 => ["ported", "nil"], + 306 => ["ported", "[$1].freeze"], + 307 => ["ported", "$1"], + 308 => ["ported", "@builder.append_arguments($1, $3)"], + 309 => ["ported", "@builder.append_arguments($1, $3)"], + 310 => ["ported", "[$2].freeze"], + 311 => ["ported", "nil"], + 312 => ["ported", "$1"], + 313 => ["ported", "$1"], + 314 => ["ported", "($1 + [$3]).freeze"], + 315 => ["ported", "($1 + [$4]).freeze"], + 316 => ["ported", "[$2].freeze"], + 317 => ["ported", "$1"], + 318 => ["ported", "$1"], + 319 => ["ported", "$1"], + 320 => ["ported", "$1"], + 321 => ["ported", "@builder.word_array($1)"], + 322 => ["ported", "@builder.word_array($1, symbols: true)"], + 323 => ["ported", "$1"], + 324 => ["ported", "$1"], + 325 => ["ported", "$1"], + 326 => ["ported", "$1"], + 327 => ["ported", "@builder.reserved_word(\"method\")"], + 328 => ["ported", "nil"], + 329 => ["ported", "@builder.body_nodes($3)"], + 330 => ["ported", "nil"], + 331 => ["ported", "@builder.parentheses($2, 336)"], + 332 => ["ported", "@builder.parentheses($2, 337)"], + 333 => ["ported", "@builder.variable(:constant, $3)"], + 334 => ["ported", "$2"], + 335 => ["ported", "@builder.array($2)"], + 336 => ["ported", "@builder.hash($2)"], + 337 => ["ported", "@builder.control(:return)"], + 338 => ["ported", "@builder.call(:yield, $3 || [])"], + 339 => ["ported", "@builder.call(:yield, [])"], + 340 => ["ported", "@builder.call(:yield, [])"], + 341 => ["ported", "@builder.call(:defined, [$5])"], + 342 => ["ported", "@builder.unary(:\"!\", $3)"], + 343 => ["ported", "@builder.reserved_word(\"not\")"], + 344 => ["ported", "@builder.block_call(@builder.call($1, []), $2)"], + 345 => ["ported", "$1"], + 346 => ["ported", "@builder.block_call($1, $2)"], + 347 => ["ported", "$1"], + 348 => ["ported", "@builder.if_node($2, $4, $5)"], + 349 => ["ported", "@builder.unless_node($2, $4, $5)"], + 350 => ["ported", "@builder.loop(:while, $2, $3)"], + 351 => ["ported", "@builder.loop(:until, $2, $3)"], + 352 => ["ported", "nil"], + 353 => ["ported", "@builder.case_node($2 || @builder.literal(nil), @builder.case_parts($5).first, @builder.case_parts($5).last)"], + 354 => ["ported", "nil"], + 355 => ["ported", "@builder.case_node(@builder.literal(nil), @builder.case_parts($4).first, @builder.case_parts($4).last)"], + 356 => ["ported", "@builder.case_node($2, @builder.case_clauses($4), nil)"], + 357 => ["ported", "@builder.for_node($2, $4, $5)"], + 358 => ["ported", "nil"], + 359 => ["ported", "@builder.class_node($2, $3, $5)"], + 360 => ["ported", "nil"], + 361 => ["ported", "@builder.singleton_class_node($3, $6)"], + 362 => ["ported", "nil"], + 363 => ["ported", "@builder.module_node($2, $4)"], + 364 => ["ported", "nil"], + 365 => ["ported", "@builder.def_node($1, $2, $4)"], + 366 => ["ported", "nil"], + 367 => ["ported", "@builder.singleton_method_node($1[0], $1[2], $2, $4)"], + 368 => ["ported", "@builder.control(:break)"], + 369 => ["ported", "@builder.control(:next)"], + 370 => ["ported", "@builder.control(:redo)"], + 371 => ["ported", "@builder.control(:retry)"], + 372 => ["ported", "$1"], + 373 => ["ported", "nil"], + 374 => ["ported", "nil"], + 375 => ["ported", "nil"], + 376 => ["ported", "nil"], + 377 => ["ported", "nil"], + 378 => ["ported", "nil"], + 379 => ["ported", "nil"], + 380 => ["ported", "nil"], + 381 => ["ported", "nil"], + 382 => ["ported", "nil"], + 383 => ["ported", "nil"], + 384 => ["ported", "nil"], + 385 => ["ported", "nil"], + 386 => ["ported", "nil"], + 387 => ["ported", "nil"], + 388 => ["ported", "nil"], + 389 => ["ported", "nil"], + 390 => ["ported", "nil"], + 391 => ["ported", "nil"], + 392 => ["ported", "nil"], + 393 => ["ported", "nil"], + 394 => ["ported", "nil"], + 395 => ["ported", "nil"], + 396 => ["ported", "nil"], + 397 => ["ported", "$1"], + 398 => ["ported", "nil"], + 399 => ["ported", "$1"], + 400 => ["ported", "@builder.elsif_node($2, $4, $5)"], + 401 => ["ported", "nil"], + 402 => ["ported", "$2"], + 403 => ["ported", "$1"], + 404 => ["ported", "$1"], + 405 => ["ported", "$1"], + 406 => ["ported", "$2"], + 407 => ["ported", "[$1].freeze"], + 408 => ["ported", "($1 + [$3]).freeze"], + 409 => ["ported", "$1"], + 410 => ["ported", "$1"], + 411 => ["ported", "$1"], + 412 => ["ported", "$1"], + 413 => ["ported", "$2"], + 414 => ["ported", "$2"], + 415 => ["ported", "nil"], + 416 => ["ported", "$1"], + 417 => ["ported", "$1"], + 418 => ["ported", "nil"], + 419 => ["ported", "nil"], + 420 => ["ported", "@builder.append_arguments($1, $4)"], + 421 => ["ported", "@builder.append_arguments($1, $2)"], + 422 => ["ported", "[nil, $1, $2].freeze"], + 423 => ["ported", "[nil, nil, $1].freeze"], + 424 => ["ported", "@builder.append_arguments($1, $2)"], + 425 => ["ported", "nil"], + 426 => ["ported", "nil"], + 427 => ["ported", "@builder.append_arguments($1, $6)"], + 428 => ["ported", "@builder.append_arguments($1, $8)"], + 429 => ["ported", "@builder.append_arguments($1, $4)"], + 430 => ["ported", "@builder.append_arguments($1, $6)"], + 431 => ["ported", "@builder.append_arguments($1, $4)"], + 432 => ["ported", "$1"], + 433 => ["ported", "@builder.append_arguments($1, $6)"], + 434 => ["ported", "@builder.append_arguments($1, $2)"], + 435 => ["ported", "@builder.append_arguments($1, $4)"], + 436 => ["ported", "@builder.append_arguments($1, $6)"], + 437 => ["ported", "@builder.append_arguments($1, $2)"], + 438 => ["ported", "@builder.append_arguments($1, $4)"], + 439 => ["ported", "@builder.append_arguments($1, $2)"], + 440 => ["ported", "@builder.append_arguments($1, $4)"], + 441 => ["ported", "$1"], + 442 => ["ported", "nil"], + 443 => ["ported", "$1"], + 444 => ["ported", "$2"], + 445 => ["ported", "$2"], + 446 => ["ported", "$1"], + 447 => ["ported", "$1"], + 448 => ["ported", "$1"], + 449 => ["ported", "$1"], + 450 => ["ported", "$1"], + 451 => ["ported", "$1"], + 452 => ["ported", "nil"], + 453 => ["ported", "nil"], + 454 => ["ported", "nil"], + 455 => ["ported", "nil"], + 456 => ["ported", "@builder.lambda_node($6, $8)"], + 457 => ["ported", "$2"], + 458 => ["ported", "$1"], + 459 => ["ported", "$2"], + 460 => ["ported", "nil"], + 461 => ["ported", "$3"], + 462 => ["ported", "$2"], + 463 => ["ported", "@builder.block_call($1, $2)"], + 464 => ["ported", "$1"], + 465 => ["ported", "$1"], + 466 => ["ported", "$1"], + 467 => ["ported", "@builder.call($1, $2 || [])"], + 468 => ["ported", "@builder.receiver_call($1, $2, $3, $4)"], + 469 => ["ported", "@builder.receiver_call($1, :\"::\", $3, $4)"], + 470 => ["ported", "@builder.receiver_call($1, :\"::\", $3, [])"], + 471 => ["ported", "$1"], + 472 => ["ported", "$1"], + 473 => ["ported", "@builder.call(:super, $2 || [])"], + 474 => ["ported", "@builder.call(:super, [])"], + 475 => ["ported", "@builder.index($1, $3 || [])"], + 476 => ["ported", "$2"], + 477 => ["ported", "$2"], + 478 => ["ported", "nil"], + 479 => ["ported", "@builder.body_nodes($6)"], + 480 => ["ported", "nil"], + 481 => ["ported", "@builder.body_nodes($6)"], + 482 => ["ported", "[$1].freeze"], + 483 => ["ported", "$2"], + 484 => ["ported", "($1 + [$3]).freeze"], + 485 => ["ported", "$1"], + 486 => ["ported", "@builder.case_chain(@builder.when_node($2, $4), $5)"], + 487 => ["ported", "$1"], + 488 => ["ported", "[$1].freeze"], + 489 => ["ported", "nil"], + 490 => ["ported", "nil"], + 491 => ["ported", "nil"], + 492 => ["ported", "nil"], + 493 => ["ported", "@builder.case_chain(@builder.when_node($5, $8), $9)"], + 494 => ["ported", "$1"], + 495 => ["ported", "$1"], + 496 => ["ported", "$1"], + 497 => ["ported", "@builder.if_node($3, [$1], nil)"], + 498 => ["ported", "@builder.unless_node($3, [$1], nil)"], + 499 => ["ported", "$1"], + 500 => ["ported", "@builder.pattern(:array, [nil, [$1], nil, nil])"], + 501 => ["ported", "@builder.pattern(:array, [[$1] + Array($3[0]), $3[1], $3[2]])"], + 502 => ["ported", "@builder.pattern(:find, $1)"], + 503 => ["ported", "@builder.pattern(:array, $1)"], + 504 => ["ported", "@builder.pattern(:hash, $1)"], + 505 => ["ported", "$1"], + 506 => ["ported", "@builder.pattern(:as, [$1, $3])"], + 507 => ["ported", "$1"], + 508 => ["ported", "@builder.pattern(:or, [$1, $3])"], + 509 => ["ported", "$1"], + 510 => ["ported", "$2"], + 511 => ["ported", "$2"], + 512 => ["ported", "$1"], + 513 => ["ported", "$1"], + 514 => ["ported", "@builder.pattern(:array, [$1, $3])"], + 515 => ["ported", "@builder.pattern(:find, [$1, $3])"], + 516 => ["ported", "@builder.pattern(:hash, [$1, $3])"], + 517 => ["ported", "@builder.pattern(:array, [$1, nil, nil, nil])"], + 518 => ["ported", "@builder.pattern(:array, [$1, $3])"], + 519 => ["ported", "@builder.pattern(:find, [$1, $3])"], + 520 => ["ported", "@builder.pattern(:hash, [$1, $3])"], + 521 => ["ported", "@builder.pattern(:array, [$1, nil, nil, nil])"], + 522 => ["ported", "@builder.pattern(:array, $2)"], + 523 => ["ported", "@builder.pattern(:find, $2)"], + 524 => ["ported", "@builder.pattern(:array, [nil, nil, nil, nil])"], + 525 => ["ported", "nil"], + 526 => ["ported", "@builder.pattern(:hash, $5)"], + 527 => ["ported", "@builder.pattern(:hash, [nil, nil, nil])"], + 528 => ["ported", "$3"], + 529 => ["ported", "[[$1], nil, nil].freeze"], + 530 => ["ported", "[$1, nil, nil].freeze"], + 531 => ["ported", "[($1 + $2), nil, nil].freeze"], + 532 => ["ported", "[$1, $2, nil].freeze"], + 533 => ["ported", "[$1, $2, $4].freeze"], + 534 => ["ported", "$1"], + 535 => ["ported", "$1"], + 536 => ["ported", "($1 + $2).freeze"], + 537 => ["ported", "[nil, $1, nil].freeze"], + 538 => ["ported", "[nil, $1, $3].freeze"], + 539 => ["ported", "[$1, $3, $5].freeze"], + 540 => ["ported", "@builder.pattern(:rest, [$2])"], + 541 => ["ported", "@builder.pattern(:rest, [nil])"], + 542 => ["ported", "$1"], + 543 => ["ported", "($1 + $3).freeze"], + 544 => ["ported", "[$1].freeze"], + 545 => ["ported", "[$1, $3].freeze"], + 546 => ["ported", "[$1, nil].freeze"], + 547 => ["ported", "[$1, nil].freeze"], + 548 => ["ported", "[[], $1].freeze"], + 549 => ["ported", "$1"], + 550 => ["ported", "($1 + [$3]).freeze"], + 551 => ["ported", "[$1, $2].freeze"], + 552 => ["ported", "[$1, nil].freeze"], + 553 => ["ported", "$1"], + 554 => ["ported", "$2"], + 555 => ["ported", "@builder.pattern(:rest, [$2])"], + 556 => ["ported", "@builder.pattern(:rest, [nil])"], + 557 => ["ported", "$1"], + 558 => ["ported", "$1"], + 559 => ["ported", "$1"], + 560 => ["ported", "$1"], + 561 => ["ported", "@builder.range(:\"..\", $1, $3)"], + 562 => ["ported", "@builder.range(:\"...\", $1, $3)"], + 563 => ["ported", "@builder.range(:\"..\", $1, nil)"], + 564 => ["ported", "@builder.range(:\"...\", $1, nil)"], + 565 => ["ported", "$1"], + 566 => ["ported", "$1"], + 567 => ["ported", "$1"], + 568 => ["ported", "@builder.range(:\"..\", nil, $2)"], + 569 => ["ported", "@builder.range(:\"...\", nil, $2)"], + 570 => ["ported", "$1"], + 571 => ["ported", "$1"], + 572 => ["ported", "$1"], + 573 => ["ported", "$1"], + 574 => ["ported", "$1"], + 575 => ["ported", "$1"], + 576 => ["ported", "$1"], + 577 => ["ported", "$1"], + 578 => ["ported", "$1"], + 579 => ["ported", "$1"], + 580 => ["ported", "@builder.pattern(:variable, [$1])"], + 581 => ["ported", "@builder.pattern(:pin, [$2])"], + 582 => ["ported", "@builder.pattern(:pin, [$2])"], + 583 => ["ported", "@builder.pattern(:begin, [$3])"], + 584 => ["ported", "@builder.variable(:constant, $2)"], + 585 => ["ported", "@builder.field($1, :\"::\", $3)"], + 586 => ["ported", "@builder.variable(:constant, $1)"], + 587 => ["ported", "@builder.rescue_chain(@builder.rescue_clause($2, $3, $5), $6)"], + 588 => ["ported", "nil"], + 589 => ["ported", "$1"], + 590 => ["ported", "$1"], + 591 => ["ported", "nil"], + 592 => ["ported", "$2"], + 593 => ["ported", "nil"], + 594 => ["ported", "@builder.body_nodes($2)"], + 595 => ["ported", "nil"], + 596 => ["ported", "$1"], + 597 => ["ported", "$1"], + 598 => ["ported", "$1"], + 599 => ["ported", "@builder.literal($1)"], + 600 => ["ported", "$1"], + 601 => ["ported", "@builder.concat_strings($1, $2)"], + 602 => ["ported", "@builder.string(@builder.join_strings($2))"], + 603 => ["ported", "@builder.xstring(@builder.join_strings($2))"], + 604 => ["ported", "@builder.regexp(@builder.join_strings($2))"], + 605 => ["ported", "$1"], + 606 => ["ported", "$1"], + 607 => ["ported", "@builder.word_array($3 || [])"], + 608 => ["ported", "[]"], + 609 => ["ported", "@builder.append_arguments($1, $2)"], + 610 => ["ported", "$1"], + 611 => ["ported", "$1.to_s + $2.to_s"], + 612 => ["ported", "@builder.word_array($3 || [])"], + 613 => ["ported", "[]"], + 614 => ["ported", "@builder.append_arguments($1, $2)"], + 615 => ["ported", "@builder.word_array($3 || [])"], + 616 => ["ported", "@builder.word_array($3 || [])"], + 617 => ["ported", "[]"], + 618 => ["ported", "@builder.append_arguments($1, $2)"], + 619 => ["ported", "nil"], + 620 => ["ported", "@builder.append_arguments($1, $2)"], + 621 => ["ported", "[]"], + 622 => ["ported", "($1 + [$2]).freeze"], + 623 => ["ported", "[]"], + 624 => ["ported", "($1 + [$2]).freeze"], + 625 => ["ported", "[]"], + 626 => ["ported", "($1 + [$2]).freeze"], + 627 => ["ported", "$1"], + 628 => ["ported", "nil"], + 629 => ["ported", "$3"], + 630 => ["ported", "nil"], + 631 => ["ported", "nil"], + 632 => ["ported", "nil"], + 633 => ["ported", "@builder.interpolation($5)"], + 634 => ["ported", "nil"], + 635 => ["ported", "nil"], + 636 => ["ported", "$1"], + 637 => ["ported", "$1"], + 638 => ["ported", "$1"], + 639 => ["ported", "$1"], + 640 => ["ported", "@builder.symbol($2)"], + 641 => ["ported", "$1"], + 642 => ["ported", "$1"], + 643 => ["ported", "@builder.symbol(@builder.join_strings($2))"], + 644 => ["ported", "$1"], + 645 => ["ported", "@builder.unary(:-, $2)"], + 646 => ["ported", "@builder.integer($1)"], + 647 => ["ported", "@builder.float($1)"], + 648 => ["ported", "@builder.literal($1)"], + 649 => ["ported", "@builder.literal($1)"], + 650 => ["ported", "@builder.variable(:instance, $1)"], + 651 => ["ported", "@builder.variable(:global, $1)"], + 652 => ["ported", "@builder.variable(:class, $1)"], + 653 => ["ported", "@builder.identifier($1)"], + 654 => ["ported", "@builder.variable(:constant, $1)"], + 655 => ["ported", "$1"], + 656 => ["ported", "@builder.literal(nil)"], + 657 => ["ported", "@builder.literal(:self)"], + 658 => ["ported", "@builder.literal(true)"], + 659 => ["ported", "@builder.literal(false)"], + 660 => ["ported", "@builder.literal(:__FILE__)"], + 661 => ["ported", "@builder.literal(:__LINE__)"], + 662 => ["ported", "@builder.literal(:__ENCODING__)"], + 663 => ["ported", "@builder.read_local($1)"], + 664 => ["ported", "$1"], + 665 => ["ported", "$1"], + 666 => ["ported", "$1"], + 667 => ["ported", "@builder.variable(:backref, $1)"], + 668 => ["ported", "@builder.variable(:backref, $1)"], + 669 => ["ported", "nil"], + 670 => ["ported", "$3"], + 671 => ["ported", "nil"], + 672 => ["ported", "$1"], + 673 => ["ported", "nil"], + 674 => ["ported", "$2"], + 675 => ["ported", "$1"], + 676 => ["ported", "nil"], + 677 => ["ported", "$2"], + 678 => ["ported", "[$1, $3, $4].freeze"], + 679 => ["ported", "[$1, nil, $2].freeze"], + 680 => ["ported", "[nil, $1, $2].freeze"], + 681 => ["ported", "$1"], + 682 => ["ported", "$1"], + 683 => ["ported", "$2"], + 684 => ["ported", "nil"], + 685 => ["ported", "[$1].freeze"], + 686 => ["ported", "[$1, $7].freeze"], + 687 => ["ported", "[$1].freeze"], + 688 => ["ported", "[$1, $5].freeze"], + 689 => ["ported", "[$1].freeze"], + 690 => ["ported", "[$1, $6].freeze"], + 691 => ["ported", "[$1].freeze"], + 692 => ["ported", "[].freeze"], + 693 => ["ported", "[$6].freeze"], + 694 => ["ported", "[].freeze"], + 695 => ["ported", "[$3].freeze"], + 696 => ["ported", "[].freeze"], + 697 => ["ported", "[$3].freeze"], + 698 => ["ported", "$1"], + 699 => ["ported", "nil"], + 700 => ["ported", "nil"], + 701 => ["ported", "$1"], + 702 => ["ported", "nil"], + 703 => ["ported", "nil"], + 704 => ["ported", "nil"], + 705 => ["ported", "$1"], + 706 => ["ported", "$1"], + 707 => ["ported", "$1"], + 708 => ["ported", "$1"], + 709 => ["ported", "$1"], + 710 => ["ported", "$1"], + 711 => ["ported", "@builder.append_arguments($1, $3)"], + 712 => ["ported", "$1"], + 713 => ["ported", "[$1, $2].freeze"], + 714 => ["ported", "[$1, 0].freeze"], + 715 => ["ported", "[$1, $2].freeze"], + 716 => ["ported", "[$1, 0].freeze"], + 717 => ["ported", "$1"], + 718 => ["ported", "@builder.append_arguments($1, $3)"], + 719 => ["ported", "$1"], + 720 => ["ported", "@builder.append_arguments($1, $3)"], + 721 => ["ported", "$1"], + 722 => ["ported", "$1"], + 723 => ["ported", "$1"], + 724 => ["ported", "$2"], + 725 => ["ported", "$1"], + 726 => ["ported", "$1"], + 727 => ["ported", "$1"], + 728 => ["ported", "$1"], + 729 => ["ported", "@builder.append_arguments($1, $3)"], + 730 => ["ported", "$1"], + 731 => ["ported", "@builder.append_arguments($1, $3)"], + 732 => ["ported", "nil"], + 733 => ["ported", "$1"], + 734 => ["ported", "[$2].freeze"], + 735 => ["ported", "$1"], + 736 => ["ported", "nil"], + 737 => ["ported", "nil"], + 738 => ["ported", "$1"], + 739 => ["ported", "$1"], + 740 => ["ported", "$2"], + 741 => ["ported", "nil"], + 742 => ["ported", "$1"], + 743 => ["ported", "nil"], + 744 => ["ported", "$1"], + 745 => ["ported", "$1"], + 746 => ["ported", "$1"], + 747 => ["ported", "[$1].freeze"], + 748 => ["ported", "($1 + [$3]).freeze"], + 749 => ["ported", "$1"], + 750 => ["ported", "@builder.pair(@builder.symbol($1), $2)"], + 751 => ["ported", "$1"], + 752 => ["ported", "$4"], + 753 => ["ported", "$2"], + 754 => ["ported", "nil"], + 755 => ["ported", "$1"], + 756 => ["ported", "$1"], + 757 => ["ported", "$1"], + 758 => ["ported", "$1"], + 759 => ["ported", "$1"], + 760 => ["ported", "$1"], + 761 => ["ported", "$1"], + 762 => ["ported", "$1"], + 763 => ["ported", "@builder.operator(\".\")"], + 764 => ["ported", "@builder.operator(\"::\")"], + 765 => ["ported", "@builder.operator(\".\")"], + 766 => ["ported", "@builder.operator(\"&.\")"], + 767 => ["ported", "$1"], + 768 => ["ported", "@builder.operator(\"::\")"], + 769 => ["ported", "nil"], + 770 => ["ported", "$1"], + 771 => ["ported", "nil"], + 772 => ["ported", "$1"], + 773 => ["ported", "$1"], + 774 => ["ported", "$1"], + 775 => ["ported", "$1"], + 776 => ["ported", "$1"], + 777 => ["ported", "nil"], + 778 => ["ported", "nil"], + 779 => ["ported", "nil"], + 780 => ["ported", "nil"], + 781 => ["ported", "nil"], + 782 => ["ported", "nil"], + }.freeze, + "compatibility_actions" => {}, + "additional_expected_conflicts" => 1 +} diff --git a/lib/arpaka/ruby_grammar.rb b/lib/arpaka/ruby_grammar.rb index 6920ecc..2761597 100644 --- a/lib/arpaka/ruby_grammar.rb +++ b/lib/arpaka/ruby_grammar.rb @@ -158,7 +158,8 @@ def self.artifacts(ruby_source: nil, parse_y: nil) rule.rhs.map { |symbol| symbol.id.s_value }]])&.first || "unsupported" } end { "parse.y" => source, "rules.json" => JSON.pretty_generate(compact) + "\n", - "runtime" => profile.fetch("runtime", {}) } + "runtime" => profile.fetch("runtime", {}), + "source_profile" => profile.fetch("source_tag", REVISION) } end def self.verify_structure(original, source, names) diff --git a/lib/lrama/ruby/version.rb b/lib/lrama/ruby/version.rb index 7bd8cc7..9d7ad9a 100644 --- a/lib/lrama/ruby/version.rb +++ b/lib/lrama/ruby/version.rb @@ -2,6 +2,6 @@ module Lrama module Ruby - VERSION = "0.1.1" + VERSION = "1.0.0" end end diff --git a/test/lrama/ruby_3_3_profile_test.rb b/test/lrama/ruby_3_3_profile_test.rb new file mode 100644 index 0000000..f5f84bf --- /dev/null +++ b/test/lrama/ruby_3_3_profile_test.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +require "test_helper" + +class Ruby33ProfileTest < Test::Unit::TestCase + PROFILE = Arpaka::Profile::RUBY.send(:load, "ruby_3_3.rb", "ruby-3.3") + + test "records the stable Ruby 3.3 source profile" do + assert_equal("v3_3_10", PROFILE.fetch("source_tag")) + assert_equal("343ea050023cfc0374fdea6fdf625b2f57b716a4", PROFILE.fetch("source_revision")) + assert_equal("0347b145280f89b0052aaaa506aa2022c9abdfa2c37677203d53a1a2b3e35861", + PROFILE.fetch("source_sha256")) + end + + test "classifies every Ruby 3.3 production" do + actions = PROFILE.fetch("actions") + + assert_false(actions.empty?) + assert_equal((1..782).to_a, actions.keys.sort) + assert_false(actions.values.any? { |classification, _| classification == "pass_through" }) + assert_equal([29, 53, 229], actions.filter_map do |id, (classification, _)| + id if classification == "unsupported" + end) + assert_include(actions.values.map(&:last), "@builder.body_nodes($1)") + assert_include(actions.values.map(&:last), "@builder.ternary($1, $3, $6)") + assert_equal("@builder.call(:defined, [$4])", actions.fetch(261).last) + assert_equal("@builder.case_node($2 || @builder.literal(nil), @builder.case_parts($5).first, @builder.case_parts($5).last)", + actions.fetch(353).last) + assert_equal("@builder.lambda_node($6, $8)", actions.fetch(456).last) + assert_equal("@builder.body_nodes($2)", actions.fetch(594).last) + assert_equal("@builder.append_arguments($1, $2)", actions.fetch(609).last) + end +end diff --git a/tool/check_package.rb b/tool/check_package.rb index 60e7ff3..103ad5c 100644 --- a/tool/check_package.rb +++ b/tool/check_package.rb @@ -51,7 +51,8 @@ abort "Ruby grammar packaged" if files.any? { |file| file.end_with?("/parse.y", "/rules.json") } %w[exe/arpaka lib/arpaka/COPYING lib/arpaka/BSDL lib/arpaka/actions.rb lib/arpaka/upstream_rules.json lib/arpaka/source.json - lib/arpaka/profile/ruby.rb lib/arpaka/profile/ruby_3_4.rb + lib/arpaka/profile/ruby.rb lib/arpaka/profile/ruby_3_3.rb + lib/arpaka/profile/ruby_3_4.rb lib/arpaka/runtime/lexer.rb.erb].each do |file| unless files.include?(file) && File.file?(File.join(spec.full_gem_path, file)) abort "Missing generation support: #{file}"