Skip to content

Round 4: close parse-conformance gaps (Rails 96.8% → 99.6%) - #6

Merged
tannevaled merged 1 commit into
mainfrom
parser-100pct-round4
Jun 26, 2026
Merged

Round 4: close parse-conformance gaps (Rails 96.8% → 99.6%)#6
tannevaled merged 1 commit into
mainfrom
parser-100pct-round4

Conversation

@tannevaled

Copy link
Copy Markdown
Contributor

Summary

Round 4 of the push to 100% parse-conformance for go-embedded-ruby. Lands the ten requested features plus the adjacent gaps each one exposed, all verified against MRI 4.0 (ruby -c).

Rails corpus (MRI-valid .rb files that parse): 3314/3423 (96.82%) → 3409/3423 (99.59%).

Features (MRI-verified)

  1. Parenthesized masgn LHS(a, b) = x, y, nested ((a, b), c), inner splat (a, *b), group-as-target a, (b, c) = …. Nested groups are a MultiAssign (nil Values) target node.
  2. Scope-resolution method callsSyslog::LOG_UPTO(x), Mod::meth arg, obj::Down x, y (+ do-block), kept distinct from scoped constants (Math::PI).
  3. Trailing <</&/|/^ line continuation — disambiguated from block-pass / block-params / heredoc / pattern-pin by lexer binary-position state.
  4. Anonymous-argument forwardingfoo(&), bar(*), g(**), to_str[*].
  5. Assignment inside a ternary branchcond ? a = b : c, x ? ENV["k"] = v : super.
  6. class/module/class << x as a valuec = class Foo < Bar; …; end.
  7. Unicode identifiers / method names / symbols / labelsdef なまえ, { 🎃: … }, :🇺🇸, :røcket (widened the identifier byte predicate; multi-byte char-literal path preserved).
  8. Safe-navigation operator methodsx&.[](i), obj&.+(y), plus the full operator-method-name set after ./&. including []/[]=.
  9. Operator/backtick method symbols + !~: `, :!~, the new NMATCH operator, and def \(cmd); end`.
  10. Beginless ranges as args & scoped const patternsfoo(...0), [...11, 11] vs ... forwarding; in Prism::CaseNode[a], Const[label:].

Adjacent gaps closed in passing

end if cond / end.html_safe (if/unless/while/until/def/class/module as expressions); super { … }; alias eql? == (fitem lists no longer over-continue a trailing operator); attribute/index array-RHS (self.x = :a, b); break/next comma values; ::Time.zone = … masgn targets; rescue => @e; predicate labels (frozen?:); rational/imaginary literals (2r, 3i, 2.5ri); nested compound assignment (a && count += 1); parameter defaults calling a same-named method (def f(secret = secret("x"))); class names with an expression receiver path (class self.class::Foo); nested do-block inside a command-argument brace block (include Module.new { define_method(:x) do … end }); option globals ($-I); constant conversion command calls (BigDecimal "0.01").

Quality

  • 100% statement coverage (CI gate), via round4_features_test.go + round4_coverage_test.go MRI-parity tables.
  • go test ./..., go vet ./..., gofmt all clean; CGO=0.

Remaining (deferred — 14 files)

Deep edges, mostly multi-issue files: regex-literal-inside-interpolation-inside-regex, an interpolation containing a paren-less command with a comma list, and a couple of constructs MRI itself rejects in isolation. No COMPILE-blocking parser gaps remain.

rbgo follow-ups (compiler cases the new AST needs)

  • Paren-masgn: a nested MultiAssign target (Values=nil) — destructure one value into sub-targets.
  • class/module-as-value: ClassDef/ModuleDef/SingletonClassDef in rvalue position must yield the body's last value.
  • Anonymous forwarding call args: SplatArg{Value:nil} / BlockPass{Value:nil} / anonymous ** (key nil, value nil) — forward the enclosing method's anonymous */**/&.
  • New literal nodes: RationalLit / ImaginaryLit (wrap an Int/Bignum/Float; ri nests).
  • RescueClause.VarTarget: assign the caught exception to a non-local target.
  • Super.Block: pass the block to super.
  • !~ desugars to !(recv =~ arg).

The end-to-end rbgo build could not be exercised in this environment (a pre-existing unrelated cloud-boot/godoom replace points at a missing sibling repo); parser-level verification (all repros parse + Rails 99.59%) stands as the functional proof.

🤖 Generated with Claude Code

Land the ten Round-4 features plus the adjacent gaps they exposed, all
verified against MRI 4.0 (`ruby -c`) and measured on the Rails corpus
(3314/3423 → 3409/3423 MRI-valid files parsing).

Features
- Parenthesized masgn LHS: `(a, b) = x, y`, nested `((a, b), c)`, inner
  splat `(a, *b)`, and as a target in a larger masgn. Represented as a
  nested MultiAssign (nil Values) target.
- Scope-resolution method calls: `Syslog::LOG_UPTO(x)`, `Mod::meth arg`,
  `obj::Down x, y` (+ do-block), distinct from scoped constants.
- Trailing bitwise/shift line continuation (`<<`/`&`/`|`/`^`), disambiguated
  from block-pass/params/heredoc/pin by lexer binary-position state.
- Anonymous-argument forwarding at call sites: `foo(&)`, `bar(*)`, `g(**)`.
- Assignment inside ternary branches: `cond ? a = b : c`.
- class/module/`class << x` definitions used as rvalues.
- Unicode identifiers / method names / symbols / labels (widened the
  identifier byte predicate; multi-byte char-literal path preserved).
- Safe-navigation operator methods: `x&.[](i)`, `obj&.+(y)`, plus the full
  operator-method-name set after `.`/`&.` including `[]`/`[]=`.
- Operator/backtick method symbols and the `!~` operator (new NMATCH token);
  backtick method definition `def \`(cmd); end`.
- Beginless ranges as arguments (`foo(...0)`, `[...11, 11]`) vs `...`
  forwarding; scope-resolved constant patterns (`in Prism::CaseNode[a]`,
  `Const[label:]`).

Adjacent gaps closed
- if/unless/while/until/def/class/module as expressions, so a trailing
  modifier or postfix chain applies (`end if cond`, `end.html_safe`).
- `super` with a block; `alias`/`undef` fitem lists no longer over-continue
  a trailing operator (`alias eql? ==`).
- Attribute/index array-RHS assignment; `break`/`next` comma values; scoped
  masgn targets (`::Time.zone = …`); rescue into a non-local target
  (`rescue => @e`); predicate/bang hash labels (`frozen?:`); rational /
  imaginary literals (`2r`, `3i`, `2.5ri`); nested compound assignment
  (`a && count += 1`); parameter defaults with a same-named method call
  (masgn suppressed); class names with an expression receiver path; nested
  do-block inside a command-argument brace block; option globals (`$-I`);
  constant conversion command calls (`BigDecimal "0.01"`).

100% statement coverage (CI gate), `go vet` clean, gofmt clean, CGO=0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@tannevaled
tannevaled merged commit 266559c into main Jun 26, 2026
9 checks passed
@tannevaled
tannevaled deleted the parser-100pct-round4 branch June 26, 2026 18:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant