Round 4: close parse-conformance gaps (Rails 96.8% → 99.6%) - #6
Merged
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
.rbfiles that parse): 3314/3423 (96.82%) → 3409/3423 (99.59%).Features (MRI-verified)
(a, b) = x, y, nested((a, b), c), inner splat(a, *b), group-as-targeta, (b, c) = …. Nested groups are aMultiAssign(nilValues) target node.Syslog::LOG_UPTO(x),Mod::meth arg,obj::Down x, y(+ do-block), kept distinct from scoped constants (Math::PI).<</&/|/^line continuation — disambiguated from block-pass / block-params / heredoc / pattern-pin by lexer binary-position state.foo(&),bar(*),g(**),to_str[*].cond ? a = b : c,x ? ENV["k"] = v : super.class << xas a value —c = class Foo < Bar; …; end.def なまえ,{ 🎃: … },:🇺🇸,:røcket(widened the identifier byte predicate; multi-byte?échar-literal path preserved).x&.[](i),obj&.+(y), plus the full operator-method-name set after./&.including[]/[]=.!~—:`,:!~, the newNMATCHoperator, anddef \(cmd); end`.foo(...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/nextcomma 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
round4_features_test.go+round4_coverage_test.goMRI-parity tables.go test ./...,go vet ./...,gofmtall 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)
MultiAssigntarget (Values=nil) — destructure one value into sub-targets.ClassDef/ModuleDef/SingletonClassDefin rvalue position must yield the body's last value.SplatArg{Value:nil}/BlockPass{Value:nil}/ anonymous**(key nil, value nil) — forward the enclosing method's anonymous*/**/&.RationalLit/ImaginaryLit(wrap an Int/Bignum/Float;rinests).RescueClause.VarTarget: assign the caught exception to a non-local target.Super.Block: pass the block tosuper.!~desugars to!(recv =~ arg).The end-to-end rbgo build could not be exercised in this environment (a pre-existing unrelated
cloud-boot/godoomreplace points at a missing sibling repo); parser-level verification (all repros parse + Rails 99.59%) stands as the functional proof.🤖 Generated with Claude Code