Index: org/jruby/ast/DRegexpNode.java =================================================================== --- org/jruby/ast/DRegexpNode.java (revision 4911) +++ org/jruby/ast/DRegexpNode.java (working copy) @@ -32,6 +32,7 @@ ***** END LICENSE BLOCK *****/ package org.jruby.ast; +import org.jruby.RubyRegexp; import org.jruby.ast.types.ILiteralNode; import org.jruby.ast.visitor.NodeVisitor; import org.jruby.evaluator.Instruction; @@ -44,17 +45,14 @@ public class DRegexpNode extends ListNode implements ILiteralNode { private final int options; private final boolean once; + private RubyRegexp onceRegexp; public DRegexpNode(ISourcePosition position) { this(position, 0, false); } public DRegexpNode(ISourcePosition position, DStrNode node, int options, boolean once) { - super(position, NodeType.DREGEXPNODE); - - this.options = options; - this.once = once; - + this(position, options, once); addAll(node); } @@ -88,4 +86,21 @@ public int getOptions() { return options; } + + /** + * For regular expressions with /o flag + * @return + */ + public RubyRegexp getOnceRegexp() { + return onceRegexp; + } + + /** + * For regular expressions with /o flag, the value in here can be used for subsequent evaluations. + * Setting will only succeed if it is a regular expression with /o flag, and the value hasn't been already set. + * @param regexp + */ + public void setOnceRegexp(RubyRegexp regexp) { + if (once && onceRegexp == null) this.onceRegexp = regexp; + } } Index: org/jruby/evaluator/ASTInterpreter.java =================================================================== --- org/jruby/evaluator/ASTInterpreter.java (revision 4911) +++ org/jruby/evaluator/ASTInterpreter.java (working copy) @@ -871,7 +871,15 @@ private static IRubyObject dregexpNode(Ruby runtime, ThreadContext context, Node node, IRubyObject self, Block aBlock) { DRegexpNode iVisited = (DRegexpNode) node; - + + RubyRegexp regexp; + if (iVisited.getOnce()) { + regexp = iVisited.getOnceRegexp(); + if (regexp != null) { + return regexp; + } + } + RubyString string = runtime.newString(new ByteList()); for (int i = 0; i < iVisited.size(); i++) { Node iterNode = iVisited.get(i); @@ -893,12 +901,18 @@ } try { - return RubyRegexp.newRegexp(runtime, string.toString(), iVisited.getOptions(), lang); + regexp = RubyRegexp.newRegexp(runtime, string.toString(), iVisited.getOptions(), lang); } catch(jregex.PatternSyntaxException e) { // System.err.println(iVisited.getValue().toString()); // e.printStackTrace(); throw runtime.newRegexpError(e.getMessage()); } + + if (iVisited.getOnce()) { + iVisited.setOnceRegexp(regexp); + } + + return regexp; } private static IRubyObject dStrNode(Ruby runtime, ThreadContext context, Node node, IRubyObject self, Block aBlock) {