Visitar URL original
Add @CRuby annotation linking Java code to CRuby functions · jruby/jruby@cb40f63 · GitHub
Skip to content

Commit cb40f63

Browse files
zevclaude
andcommitted
Add @cruby annotation linking Java code to CRuby functions
Adds org.jruby.anno.CRuby (repeatable, RUNTIME, @documented) to replace "// MRI: rb_foo" comments, so the mapping can be audited by tools and used by docs and runtime tooling. Converts the MRI comments in RubyMatchData as a first use, and notes the convention in CONTRIBUTING.md. tool/cruby_annotations.rb checks annotations against a CRuby checkout (check) and reports the comment-style references not yet converted (survey). tool/cruby_annotations_test.rb tests both against a small fake CRuby tree. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 09cff75 commit cb40f63

5 files changed

Lines changed: 771 additions & 6 deletions

File tree

‎CONTRIBUTING.md‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,18 @@ Other documentation in this repository and in the wiki explain in more detail ho
4343

4444
Other `test` and `spec` suites may also be appropriate depending on what functionality you are working on.
4545

46+
### Linking Java code to CRuby
47+
48+
When a method, class or field implements or ports a CRuby C function or macro, annotate it with `@CRuby` (`org.jruby.anno.CRuby`) rather than writing a `// MRI: rb_foo` comment:
49+
50+
```java
51+
@CRuby(value = "match_begin", file = "re.c")
52+
@JRubyMethod
53+
public IRubyObject begin(ThreadContext context, IRubyObject index) {
54+
```
55+
56+
`file` is optional. Repeat the annotation when one Java method covers several C functions, and use `note` for qualifiers such as `note = "first half"`. `tool/cruby_annotations.rb` checks the annotations against a CRuby checkout.
57+
4658
## Testing
4759

4860
See [BUILDING.md](BUILDING.md) for more details.

‎core/src/main/java/org/jruby/RubyMatchData.java‎

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import org.joni.Region;
4242
import org.joni.exception.JOniException;
4343
import org.joni.exception.ValueException;
44+
import org.jruby.anno.CRuby;
4445
import org.jruby.anno.JRubyClass;
4546
import org.jruby.anno.JRubyMethod;
4647
import org.jruby.api.Convert;
@@ -558,7 +559,7 @@ public static int backrefNumber(ThreadContext context, Regex pattern, Region reg
558559
return toInt(context, obj);
559560
}
560561

561-
// MRI: namev_to_backref_number
562+
@CRuby(value = "namev_to_backref_number", file = "re.c")
562563
private int namevToBackrefNumber(ThreadContext context, IRubyObject name) {
563564
int num = -1;
564565

@@ -583,7 +584,7 @@ private int nameToBackrefError(ThreadContext context, String name) {
583584
throw indexError(context, "undefined group name reference " + name);
584585
}
585586

586-
// MRI: match_ary_subseq
587+
@CRuby(value = "match_ary_subseq", file = "re.c")
587588
private IRubyObject matchArySubseq(ThreadContext context, int beg, int len, RubyArray result) {
588589
assert result != null;
589590

@@ -606,7 +607,7 @@ private IRubyObject matchArySubseq(ThreadContext context, int beg, int len, Ruby
606607
return result;
607608
}
608609

609-
// MRI: match_ary_aref
610+
@CRuby(value = "match_ary_aref", file = "re.c")
610611
private IRubyObject matchAryAref(ThreadContext context, IRubyObject index, RubyArray result) {
611612
int[] begLen = new int[2];
612613
int numRegs = regs.getNumRegs();
@@ -678,9 +679,7 @@ public IRubyObject size(ThreadContext context) {
678679
return regs == null ? RubyFixnum.one(context.runtime) : asFixnum(context, regs.getNumRegs());
679680
}
680681

681-
/**
682-
* MRI: match_begin
683-
*/
682+
@CRuby(value = "match_begin", file = "re.c")
684683
@JRubyMethod
685684
public IRubyObject begin(ThreadContext context, IRubyObject index) {
686685
check(context);
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/***** BEGIN LICENSE BLOCK *****
2+
* Version: EPL 2.0/GPL 2.0/LGPL 2.1
3+
*
4+
* The contents of this file are subject to the Eclipse Public
5+
* License Version 2.0 (the "License"); you may not use this file
6+
* except in compliance with the License. You may obtain a copy of
7+
* the License at http://www.eclipse.org/legal/epl-v20.html
8+
*
9+
* Software distributed under the License is distributed on an "AS
10+
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11+
* implied. See the License for the specific language governing
12+
* rights and limitations under the License.
13+
*
14+
* Alternatively, the contents of this file may be used under the terms of
15+
* either of the GNU General Public License Version 2 or later (the "GPL"),
16+
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
17+
* in which case the provisions of the GPL or the LGPL are applicable instead
18+
* of those above. If you wish to allow use of your version of this file only
19+
* under the terms of either the GPL or the LGPL, and not to allow others to
20+
* use your version of this file under the terms of the EPL, indicate your
21+
* decision by deleting the provisions above and replace them with the notice
22+
* and other provisions required by the GPL or the LGPL. If you do not delete
23+
* the provisions above, a recipient may use your version of this file under
24+
* the terms of any one of the EPL, the GPL or the LGPL.
25+
***** END LICENSE BLOCK *****/
26+
27+
package org.jruby.anno;
28+
29+
import java.lang.annotation.Documented;
30+
import java.lang.annotation.ElementType;
31+
import java.lang.annotation.Repeatable;
32+
import java.lang.annotation.Retention;
33+
import java.lang.annotation.RetentionPolicy;
34+
import java.lang.annotation.Target;
35+
36+
/**
37+
* Links a Java declaration to the CRuby C function or macro it implements or was ported from.
38+
*
39+
* <pre>
40+
* &#64;CRuby("match_size")
41+
* &#64;CRuby(value = "match_begin", file = "re.c")
42+
* &#64;CRuby(value = "ary_reject_bang", file = "array.c")
43+
* &#64;CRuby(value = "reject_bang_i", file = "array.c")
44+
* &#64;CRuby(value = "rb_str_count", note = "first half")
45+
* </pre>
46+
*
47+
* Use it in place of a {@code // MRI: rb_foo} comment or a Javadoc that only names the C function, so tools can
48+
* audit the mapping and documentation can link to the C source. It is retained at runtime so that tools working from a
49+
* live JRuby (IRB, RI, language servers) can find it by reflecting on the Java method behind a Ruby method.
50+
*
51+
* {@code tool/cruby_annotations.rb} checks the names and files against a CRuby checkout.
52+
*/
53+
@Documented
54+
@Retention(RetentionPolicy.RUNTIME)
55+
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.TYPE, ElementType.FIELD})
56+
@Repeatable(CRuby.List.class)
57+
public @interface CRuby {
58+
/**
59+
* The C function or macro, e.g. "match_integer_at".
60+
*/
61+
String value();
62+
63+
/**
64+
* The C source file defining it, relative to the CRuby root, e.g. "re.c". Optional, mainly useful when the
65+
* name is defined in more than one file.
66+
*/
67+
String file() default "";
68+
69+
/**
70+
* Free text qualifying the link, e.g. "first half" or "loop body".
71+
*/
72+
String note() default "";
73+
74+
/**
75+
* Container for repeated {@link CRuby} annotations; not used directly.
76+
*/
77+
@Documented
78+
@Retention(RetentionPolicy.RUNTIME)
79+
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.TYPE, ElementType.FIELD})
80+
@interface List {
81+
CRuby[] value();
82+
}
83+
}

0 commit comments

Comments
 (0)