PageRenderTime 136ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 2ms

/text/src/test/resources/examples/java/jruby.in.java

https://github.com/rimolive/core
Java | 13963 lines | 12550 code | 421 blank | 992 comment | 360 complexity | 177e0295a7887cd9ab9c9ef722d9455d MD5 | raw file
Possible License(s): EPL-1.0, MPL-2.0-no-copyleft-exception
  1. package org.jruby;
  2. public enum CompatVersion {
  3. RUBY1_8, RUBY1_9, BOTH;
  4. public static CompatVersion getVersionFromString(String compatString) {
  5. if (compatString.equalsIgnoreCase("RUBY1_8")) {
  6. return CompatVersion.RUBY1_8;
  7. } else if (compatString.equalsIgnoreCase("RUBY1_9")) {
  8. return CompatVersion.RUBY1_9;
  9. } else {
  10. return null;
  11. }
  12. }
  13. }
  14. /***** BEGIN LICENSE BLOCK *****
  15. * Version: CPL 1.0/GPL 2.0/LGPL 2.1
  16. *
  17. * The contents of this file are subject to the Common Public
  18. * License Version 1.0 (the "License"); you may not use this file
  19. * except in compliance with the License. You may obtain a copy of
  20. * the License at http://www.eclipse.org/legal/cpl-v10.html
  21. *
  22. * Software distributed under the License is distributed on an "AS
  23. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  24. * implied. See the License for the specific language governing
  25. * rights and limitations under the License.
  26. *
  27. * Copyright (C) 2007 Damian Steer <pldms@mac.com>
  28. *
  29. * Alternatively, the contents of this file may be used under the terms of
  30. * either of the GNU General Public License Version 2 or later (the "GPL"),
  31. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  32. * in which case the provisions of the GPL or the LGPL are applicable instead
  33. * of those above. If you wish to allow use of your version of this file only
  34. * under the terms of either the GPL or the LGPL, and not to allow others to
  35. * use your version of this file under the terms of the CPL, indicate your
  36. * decision by deleting the provisions above and replace them with the notice
  37. * and other provisions required by the GPL or the LGPL. If you do not delete
  38. * the provisions above, a recipient may use your version of this file under
  39. * the terms of any one of the CPL, the GPL or the LGPL.
  40. ***** END LICENSE BLOCK *****/
  41. package org.jruby;
  42. /**
  43. * An almost entirely useless interface for those objects that we _really_ want
  44. * to finalise.
  45. *
  46. * @author pldms
  47. *
  48. */
  49. public interface Finalizable {
  50. public void finalize();
  51. }
  52. /***** BEGIN LICENSE BLOCK *****
  53. * Version: CPL 1.0/GPL 2.0/LGPL 2.1
  54. *
  55. * The contents of this file are subject to the Common Public
  56. * License Version 1.0 (the "License"); you may not use this file
  57. * except in compliance with the License. You may obtain a copy of
  58. * the License at http://www.eclipse.org/legal/cpl-v10.html
  59. *
  60. * Software distributed under the License is distributed on an "AS
  61. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  62. * implied. See the License for the specific language governing
  63. * rights and limitations under the License.
  64. *
  65. * Copyright (C) 2002 Benoit Cerrina <b.cerrina@wanadoo.fr>
  66. * Copyright (C) 2002 Jan Arne Petersen <jpetersen@uni-bonn.de>
  67. *
  68. * Alternatively, the contents of this file may be used under the terms of
  69. * either of the GNU General Public License Version 2 or later (the "GPL"),
  70. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  71. * in which case the provisions of the GPL or the LGPL are applicable instead
  72. * of those above. If you wish to allow use of your version of this file only
  73. * under the terms of either the GPL or the LGPL, and not to allow others to
  74. * use your version of this file under the terms of the CPL, indicate your
  75. * decision by deleting the provisions above and replace them with the notice
  76. * and other provisions required by the GPL or the LGPL. If you do not delete
  77. * the provisions above, a recipient may use your version of this file under
  78. * the terms of any one of the CPL, the GPL or the LGPL.
  79. ***** END LICENSE BLOCK *****/
  80. package org.jruby;
  81. /**
  82. * Error numbers.
  83. * @fixme
  84. * this interface is a big hack defining a bunch of arbitrary valor as system call error numbers
  85. * this is actually because I need them but will probably need to be changed to something smarter
  86. * sooner or later.
  87. * The purpose of this class it to help implement the Errno module which in turn in needed by rubicon.
  88. * @author Benoit Cerrina
  89. **/
  90. public interface IErrno
  91. {
  92. int EPERM = 1;
  93. int ENOENT = 2;
  94. int ESRCH = 3;
  95. int EINTR = 4;
  96. int EIO = 5;
  97. int ENXIO = 6;
  98. int E2BIG = 7;
  99. int ENOEXEC = 8;
  100. int EBADF = 9;
  101. int ECHILD = 10;
  102. int EDEADLK = 11;
  103. int ENOMEM = 12;
  104. int EACCES = 13;
  105. int EFAULT = 14;
  106. int ENOTBLK = 15;
  107. int EBUSY = 16;
  108. int EEXIST = 17;
  109. int EXDEV = 18;
  110. int ENODEV = 19;
  111. int ENOTDIR = 20;
  112. int EISDIR = 21;
  113. int EINVAL = 22;
  114. int ENFILE = 23;
  115. int EMFILE = 24;
  116. int ENOTTY = 25;
  117. int ETXTBSY = 26;
  118. int EFBIG = 27;
  119. int ENOSPC = 28;
  120. int ESPIPE = 29;
  121. int EROFS = 30;
  122. int EMLINK = 31;
  123. int EPIPE = 32;
  124. int EDOM = 33;
  125. int ERANGE = 34;
  126. int EWOULDBLOCK = 35;
  127. int EAGAIN = 35;
  128. int EINPROGRESS = 36;
  129. int EALREADY = 37;
  130. int ENOTSOCK = 38;
  131. int EDESTADDRREQ = 39;
  132. int EMSGSIZE = 40;
  133. int EPROTOTYPE = 41;
  134. int ENOPROTOOPT = 42;
  135. int EPROTONOSUPPORT = 43;
  136. int ESOCKTNOSUPPORT = 44;
  137. int EOPNOTSUPP = 45;
  138. int EPFNOSUPPORT = 46;
  139. int EAFNOSUPPORT = 47;
  140. int EADDRINUSE = 48;
  141. int EADDRNOTAVAIL = 49;
  142. int ENETDOWN = 50;
  143. int ENETUNREACH = 51;
  144. int ENETRESET = 52;
  145. int ECONNABORTED = 53;
  146. int ECONNRESET = 54;
  147. int ENOBUFS = 55;
  148. int EISCONN = 56;
  149. int ENOTCONN = 57;
  150. int ESHUTDOWN = 58;
  151. int ETOOMANYREFS = 59;
  152. int ETIMEDOUT = 60;
  153. int ECONNREFUSED = 61;
  154. int ELOOP = 62;
  155. int ENAMETOOLONG = 63;
  156. int EHOSTDOWN = 64;
  157. int EHOSTUNREACH = 65;
  158. int ENOTEMPTY = 66;
  159. int EUSERS = 68;
  160. int EDQUOT = 69;
  161. int ESTALE = 70;
  162. int EREMOTE = 71;
  163. int ENOLCK = 77;
  164. int ENOSYS = 78;
  165. int EOVERFLOW = 84;
  166. int EIDRM = 90;
  167. int ENOMSG = 91;
  168. int EILSEQ = 92;
  169. int EBADMSG = 94;
  170. int EMULTIHOP = 95;
  171. int ENODATA = 96;
  172. int ENOLINK = 97;
  173. int ENOSR = 98;
  174. int ENOSTR = 99;
  175. int EPROTO = 100;
  176. int ETIME = 101;
  177. int EOPNOTSUPP_DARWIN = 102;
  178. }
  179. /*
  180. ***** BEGIN LICENSE BLOCK *****
  181. * Version: CPL 1.0/GPL 2.0/LGPL 2.1
  182. *
  183. * The contents of this file are subject to the Common Public
  184. * License Version 1.0 (the "License"); you may not use this file
  185. * except in compliance with the License. You may obtain a copy of
  186. * the License at http://www.eclipse.org/legal/cpl-v10.html
  187. *
  188. * Software distributed under the License is distributed on an "AS
  189. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  190. * implied. See the License for the specific language governing
  191. * rights and limitations under the License.
  192. *
  193. * Copyright (C) 2002-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
  194. * Copyright (C) 2004-2006 Thomas E Enebo <enebo@acm.org>
  195. * Copyright (C) 2005 Charles O Nutter <headius@headius.com>
  196. * Copyright (C) 2006 Miguel Covarrubias <mlcovarrubias@gmail.com>
  197. * Copyright (C) 2007 William N Dortch <bill.dortch@gmail.com>
  198. *
  199. * Alternatively, the contents of this file may be used under the terms of
  200. * either of the GNU General Public License Version 2 or later (the "GPL"),
  201. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  202. * in which case the provisions of the GPL or the LGPL are applicable instead
  203. * of those above. If you wish to allow use of your version of this file only
  204. * under the terms of either the GPL or the LGPL, and not to allow others to
  205. * use your version of this file under the terms of the CPL, indicate your
  206. * decision by deleting the provisions above and replace them with the notice
  207. * and other provisions required by the GPL or the LGPL. If you do not delete
  208. * the provisions above, a recipient may use your version of this file under
  209. * the terms of any one of the CPL, the GPL or the LGPL.
  210. ***** END LICENSE BLOCK *****/
  211. package org.jruby;
  212. import java.util.List;
  213. import java.util.Map;
  214. import org.jruby.internal.runtime.methods.DynamicMethod;
  215. import org.jruby.runtime.builtin.IRubyObject;
  216. import org.jruby.runtime.builtin.Variable;
  217. /**
  218. * This class is used to provide an intermediate superclass for modules and classes that include
  219. * other modules. It inserts itself as the immediate superClass of the includer, but defers all
  220. * module methods to the actual superclass. Multiple of these intermediate superclasses can be
  221. * added for multiple included modules.
  222. *
  223. * This allows the normal superclass-based searches (searchMethod, getConstant, etc) to traverse
  224. * the superclass ancestors as normal while the included modules do not actually show up in
  225. * direct inheritance traversal.
  226. *
  227. * @see org.jruby.RubyModule
  228. */
  229. public final class IncludedModuleWrapper extends RubyClass {
  230. private final RubyModule delegate;
  231. public IncludedModuleWrapper(Ruby runtime, RubyClass superClass, RubyModule delegate) {
  232. super(runtime, superClass, false);
  233. this.delegate = delegate;
  234. this.metaClass = delegate.metaClass;
  235. }
  236. /**
  237. * Overridden newIncludeClass implementation to allow attaching future includes to the correct module
  238. * (i.e. the one to which this is attached)
  239. *
  240. * @see org.jruby.RubyModule#newIncludeClass(RubyClass)
  241. */
  242. @Override
  243. public IncludedModuleWrapper newIncludeClass(RubyClass superClass) {
  244. IncludedModuleWrapper includedModule = new IncludedModuleWrapper(getRuntime(), superClass, getNonIncludedClass());
  245. // include its parent (and in turn that module's parents)
  246. if (getSuperClass() != null) {
  247. includedModule.includeModule(getSuperClass());
  248. }
  249. return includedModule;
  250. }
  251. @Override
  252. public boolean isModule() {
  253. return false;
  254. }
  255. @Override
  256. public boolean isClass() {
  257. return false;
  258. }
  259. @Override
  260. public boolean isIncluded() {
  261. return true;
  262. }
  263. @Override
  264. public boolean isImmediate() {
  265. return true;
  266. }
  267. @Override
  268. public void setMetaClass(RubyClass newRubyClass) {
  269. throw new UnsupportedOperationException("An included class is only a wrapper for a module");
  270. }
  271. @Override
  272. public Map<String, DynamicMethod> getMethods() {
  273. return delegate.getMethods();
  274. }
  275. @Override
  276. public void addMethod(String name, DynamicMethod method) {
  277. throw new UnsupportedOperationException("An included class is only a wrapper for a module");
  278. }
  279. public void setMethods(Map newMethods) {
  280. throw new UnsupportedOperationException("An included class is only a wrapper for a module");
  281. }
  282. @Override
  283. public String getName() {
  284. return delegate.getName();
  285. }
  286. @Override
  287. public RubyModule getNonIncludedClass() {
  288. return delegate;
  289. }
  290. @Override
  291. public RubyClass getRealClass() {
  292. return getSuperClass().getRealClass();
  293. }
  294. @Override
  295. protected boolean isSame(RubyModule module) {
  296. return delegate.isSame(module);
  297. }
  298. /**
  299. * We don't want to reveal ourselves to Ruby code, so delegate this
  300. * operation.
  301. */
  302. @Override
  303. public IRubyObject id() {
  304. return delegate.id();
  305. }
  306. //
  307. // VARIABLE TABLE METHODS - pass to delegate
  308. //
  309. @Override
  310. protected boolean variableTableContains(String name) {
  311. return delegate.variableTableContains(name);
  312. }
  313. @Override
  314. protected boolean variableTableFastContains(String internedName) {
  315. return delegate.variableTableFastContains(internedName);
  316. }
  317. @Override
  318. protected IRubyObject variableTableFetch(String name) {
  319. return delegate.variableTableFetch(name);
  320. }
  321. @Override
  322. protected IRubyObject variableTableFastFetch(String internedName) {
  323. return delegate.variableTableFastFetch(internedName);
  324. }
  325. @Override
  326. protected IRubyObject variableTableStore(String name, IRubyObject value) {
  327. return delegate.variableTableStore(name, value);
  328. }
  329. @Override
  330. protected IRubyObject variableTableFastStore(String internedName, IRubyObject value) {
  331. return delegate.variableTableFastStore(internedName, value);
  332. }
  333. @Override
  334. protected IRubyObject variableTableRemove(String name) {
  335. return delegate.variableTableRemove(name);
  336. }
  337. @Override
  338. protected VariableTableEntry[] variableTableGetTable() {
  339. return delegate.variableTableGetTable();
  340. }
  341. @Override
  342. protected int variableTableGetSize() {
  343. return delegate.variableTableGetSize();
  344. }
  345. @Override
  346. protected void variableTableSync(List<Variable<IRubyObject>> vars) {
  347. delegate.variableTableSync(vars);
  348. }
  349. @Override
  350. protected IRubyObject variableTableReadLocked(VariableTableEntry entry) {
  351. return delegate.variableTableReadLocked(entry);
  352. }
  353. /**
  354. * Method to help ease transition to new variables implementation.
  355. * Will likely be deprecated in the near future.
  356. */
  357. @SuppressWarnings("unchecked")
  358. @Override
  359. @Deprecated // born deprecated
  360. protected Map variableTableGetMap() {
  361. return delegate.variableTableGetMap();
  362. }
  363. /**
  364. * Method to help ease transition to new variables implementation.
  365. * Will likely be deprecated in the near future.
  366. */
  367. @SuppressWarnings("unchecked")
  368. @Override
  369. @Deprecated // born deprecated
  370. protected Map variableTableGetMap(Map map) {
  371. return delegate.variableTableGetMap(map);
  372. }
  373. //
  374. // CONSTANT TABLE METHODS - pass to delegate
  375. //
  376. @Override
  377. protected boolean constantTableContains(String name) {
  378. return delegate.constantTableContains(name);
  379. }
  380. @Override
  381. protected boolean constantTableFastContains(String internedName) {
  382. return delegate.constantTableFastContains(internedName);
  383. }
  384. @Override
  385. protected IRubyObject constantTableFetch(String name) {
  386. return delegate.constantTableFetch(name);
  387. }
  388. @Override
  389. protected IRubyObject constantTableFastFetch(String internedName) {
  390. return delegate.constantTableFastFetch(internedName);
  391. }
  392. @Override
  393. protected IRubyObject constantTableStore(String name, IRubyObject value) {
  394. // FIXME: legal here? may want UnsupportedOperationException
  395. return delegate.constantTableStore(name, value);
  396. }
  397. @Override
  398. protected IRubyObject constantTableFastStore(String internedName, IRubyObject value) {
  399. // FIXME: legal here? may want UnsupportedOperationException
  400. return delegate.constantTableFastStore(internedName, value);
  401. }
  402. @Override
  403. protected IRubyObject constantTableRemove(String name) {
  404. // this _is_ legal (when removing an undef)
  405. return delegate.constantTableRemove(name);
  406. }
  407. @Override
  408. protected ConstantTableEntry[] constantTableGetTable() {
  409. return delegate.constantTableGetTable();
  410. }
  411. @Override
  412. protected int constantTableGetSize() {
  413. return delegate.constantTableGetSize();
  414. }
  415. @Override
  416. protected void constantTableSync(List<Variable<IRubyObject>> vars) {
  417. // FIXME: legal here? may want UnsupportedOperationException
  418. delegate.constantTableSync(vars);
  419. }
  420. /**
  421. * Method to help ease transition to new variables implementation.
  422. * Will likely be deprecated in the near future.
  423. */
  424. @SuppressWarnings("unchecked")
  425. @Override
  426. @Deprecated // born deprecated
  427. protected Map constantTableGetMap() {
  428. return delegate.constantTableGetMap();
  429. }
  430. /**
  431. * Method to help ease transition to new variables implementation.
  432. * Will likely be deprecated in the near future.
  433. */
  434. @SuppressWarnings("unchecked")
  435. @Override
  436. @Deprecated // born deprecated
  437. protected Map constantTableGetMap(Map map) {
  438. return delegate.constantTableGetMap(map);
  439. }
  440. }
  441. /***** BEGIN LICENSE BLOCK *****
  442. * Version: CPL 1.0/GPL 2.0/LGPL 2.1
  443. *
  444. * The contents of this file are subject to the Common Public
  445. * License Version 1.0 (the "License"); you may not use this file
  446. * except in compliance with the License. You may obtain a copy of
  447. * the License at http://www.eclipse.org/legal/cpl-v10.html
  448. *
  449. * Software distributed under the License is distributed on an "AS
  450. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  451. * implied. See the License for the specific language governing
  452. * rights and limitations under the License.
  453. *
  454. * Copyright (C) 2007 Charles Nutter <charles.o.nutter@sun.com>
  455. * Copyright (C) 2008 MenTaLguY <mental@rydia.net>
  456. *
  457. * Alternatively, the contents of this file may be used under the terms of
  458. * either of the GNU General Public License Version 2 or later (the "GPL"),
  459. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  460. * in which case the provisions of the GPL or the LGPL are applicable instead
  461. * of those above. If you wish to allow use of your version of this file only
  462. * under the terms of either the GPL or the LGPL, and not to allow others to
  463. * use your version of this file under the terms of the CPL, indicate your
  464. * decision by deleting the provisions above and replace them with the notice
  465. * and other provisions required by the GPL or the LGPL. If you do not delete
  466. * the provisions above, a recipient may use your version of this file under
  467. * the terms of any one of the CPL, the GPL or the LGPL.
  468. ***** END LICENSE BLOCK *****/
  469. package org.jruby;
  470. import java.applet.Applet;
  471. import java.awt.BorderLayout;
  472. import java.awt.Color;
  473. import java.awt.Container;
  474. import java.awt.EventQueue;
  475. import java.awt.Font;
  476. import java.awt.Insets;
  477. import java.awt.Graphics;
  478. import java.awt.GraphicsConfiguration;
  479. import java.awt.GraphicsEnvironment;
  480. import java.awt.image.VolatileImage;
  481. import java.io.IOException;
  482. import java.io.InputStream;
  483. import java.io.PrintStream;
  484. import java.net.URL;
  485. import java.util.Arrays;
  486. import java.lang.reflect.InvocationTargetException;
  487. import org.jruby.anno.JRubyMethod;
  488. import org.jruby.demo.TextAreaReadline;
  489. import org.jruby.javasupport.JavaUtil;
  490. import org.jruby.runtime.Block;
  491. import org.jruby.runtime.ThreadContext;
  492. import org.jruby.runtime.builtin.IRubyObject;
  493. import javax.swing.JScrollPane;
  494. import javax.swing.JTextPane;
  495. /**
  496. * @author <a href="mailto:mental@rydia.net">MenTaLguY</a>
  497. *
  498. * The JRubyApplet class provides a simple way to write Java applets using
  499. * JRuby without needing to create a custom Java applet class. At applet
  500. * initialization time, JRubyApplet starts up a JRuby runtime, then evaluates
  501. * the scriptlet given as the "eval" applet parameter.
  502. *
  503. * The Java applet instance is available to the Ruby script as
  504. * JRUBY_APPLET; the script can define callbacks for applet start, stop,
  505. * and destroy by passing blocks to JRUBY_APPLET.on_start,
  506. * JRUBY_APPLET.on_stop, and JRUBY_APPLET.on_destroy, respectively.
  507. *
  508. * Ruby code can install a custom paint callback using JRUBY_APPLET.on_paint
  509. * (the Graphics2D object is passed as an argument to the callback). By
  510. * default, JRubyApplet painting is double-buffered, but you can select
  511. * single-buffered painting via JRUBY_APPLET.double_buffered = false.
  512. *
  513. * The applet's background color can be set via JRUBY_APPLET.background_color=.
  514. * You may want to set it to nil if you're not using double-buffering, so that
  515. * no background color will be drawn (your own paint code is then responsible
  516. * for filling the area).
  517. *
  518. * Beyond these things, you should be able to use JRuby's Java integration
  519. * to do whatever you would do in Java with the applet instance.
  520. *
  521. */
  522. public class JRubyApplet extends Applet {
  523. private Ruby runtime;
  524. private boolean doubleBuffered = true;
  525. private Color backgroundColor = Color.WHITE;
  526. private RubyProc startProc;
  527. private RubyProc stopProc;
  528. private RubyProc destroyProc;
  529. private RubyProc paintProc;
  530. private Graphics priorGraphics;
  531. private IRubyObject wrappedGraphics;
  532. private VolatileImage backBuffer;
  533. private Graphics backBufferGraphics;
  534. private Facade facade;
  535. private interface Facade {
  536. public InputStream getInputStream();
  537. public PrintStream getOutputStream();
  538. public PrintStream getErrorStream();
  539. public void attach(Ruby runtime, Applet applet);
  540. public void destroy();
  541. }
  542. private static RubyProc blockToProc(Ruby runtime, Block block) {
  543. if (block.isGiven()) {
  544. RubyProc proc = block.getProcObject();
  545. if (proc == null) {
  546. proc = RubyProc.newProc(runtime, block, block.type);
  547. }
  548. return proc;
  549. } else {
  550. return null;
  551. }
  552. }
  553. private boolean getBooleanParameter(String name, boolean defaultValue) {
  554. String value = getParameter(name);
  555. if ( value != null ) {
  556. return value.equals("true");
  557. } else {
  558. return defaultValue;
  559. }
  560. }
  561. private InputStream getCodeResourceAsStream(String name) {
  562. if (name == null) {
  563. return null;
  564. }
  565. try {
  566. final URL directURL = new URL(getCodeBase(), name);
  567. return directURL.openStream();
  568. } catch (IOException e) {
  569. }
  570. return JRubyApplet.class.getClassLoader().getResourceAsStream(name);
  571. }
  572. private static void safeInvokeAndWait(Runnable runnable) throws InvocationTargetException, InterruptedException {
  573. if (EventQueue.isDispatchThread()) {
  574. try {
  575. runnable.run();
  576. } catch (Exception e) {
  577. throw new InvocationTargetException(e);
  578. }
  579. } else {
  580. EventQueue.invokeAndWait(runnable);
  581. }
  582. }
  583. public static class RubyMethods {
  584. @JRubyMethod
  585. public static IRubyObject on_start(IRubyObject recv, Block block) {
  586. JRubyApplet applet = (JRubyApplet)recv.dataGetStruct();
  587. synchronized (applet) {
  588. applet.startProc = blockToProc(applet.runtime, block);
  589. }
  590. return recv;
  591. }
  592. @JRubyMethod
  593. public static IRubyObject on_stop(IRubyObject recv, Block block) {
  594. JRubyApplet applet = (JRubyApplet)recv.dataGetStruct();
  595. synchronized (applet) {
  596. applet.stopProc = blockToProc(applet.runtime, block);
  597. }
  598. return recv;
  599. }
  600. @JRubyMethod
  601. public static IRubyObject on_destroy(IRubyObject recv, Block block) {
  602. JRubyApplet applet = (JRubyApplet)recv.dataGetStruct();
  603. synchronized (applet) {
  604. applet.destroyProc = blockToProc(applet.runtime, block);
  605. }
  606. return recv;
  607. }
  608. @JRubyMethod
  609. public static IRubyObject on_paint(IRubyObject recv, Block block) {
  610. JRubyApplet applet = (JRubyApplet)recv.dataGetStruct();
  611. synchronized (applet) {
  612. applet.paintProc = blockToProc(applet.runtime, block);
  613. applet.repaint();
  614. }
  615. return recv;
  616. }
  617. }
  618. @Override
  619. public void init() {
  620. super.init();
  621. if (getBooleanParameter("jruby.console", false)) {
  622. facade = new ConsoleFacade(getParameter("jruby.banner"));
  623. } else {
  624. facade = new TrivialFacade();
  625. }
  626. synchronized (this) {
  627. if (runtime != null) {
  628. return;
  629. }
  630. final RubyInstanceConfig config = new RubyInstanceConfig() {{
  631. setInput(facade.getInputStream());
  632. setOutput(facade.getOutputStream());
  633. setError(facade.getErrorStream());
  634. setObjectSpaceEnabled(getBooleanParameter("jruby.objectspace", false));
  635. }};
  636. Ruby.setSecurityRestricted(true);
  637. runtime = Ruby.newInstance(config);
  638. }
  639. final String scriptName = getParameter("jruby.script");
  640. final InputStream scriptStream = getCodeResourceAsStream(scriptName);
  641. final String evalString = getParameter("jruby.eval");
  642. try {
  643. final JRubyApplet applet = this;
  644. safeInvokeAndWait(new Runnable() {
  645. public void run() {
  646. applet.setLayout(new BorderLayout());
  647. applet.facade.attach(applet.runtime, applet);
  648. if (scriptStream != null) {
  649. applet.runtime.runFromMain(scriptStream, scriptName);
  650. }
  651. if (evalString != null) {
  652. applet.runtime.evalScriptlet(evalString);
  653. }
  654. }
  655. });
  656. } catch (InterruptedException e) {
  657. } catch (InvocationTargetException e) {
  658. throw new RuntimeException("Error running script", e.getCause());
  659. }
  660. }
  661. private void invokeCallback(final RubyProc proc, final IRubyObject[] args) {
  662. if (proc == null) {
  663. return;
  664. }
  665. final Ruby runtime = this.runtime;
  666. try {
  667. safeInvokeAndWait(new Runnable() {
  668. public void run() {
  669. ThreadContext context = runtime.getCurrentContext();
  670. proc.call(context, args);
  671. }
  672. });
  673. } catch (InterruptedException e) {
  674. } catch (InvocationTargetException e) {
  675. throw new RuntimeException("Ruby callback failed", e.getCause());
  676. }
  677. }
  678. public synchronized void setBackgroundColor(Color color) {
  679. backgroundColor = color;
  680. repaint();
  681. }
  682. public synchronized Color getBackgroundColor() {
  683. return backgroundColor;
  684. }
  685. public synchronized boolean isDoubleBuffered() {
  686. return doubleBuffered;
  687. }
  688. public synchronized void setDoubleBuffered(boolean shouldBuffer) {
  689. doubleBuffered = shouldBuffer;
  690. repaint();
  691. }
  692. @Override
  693. public synchronized void start() {
  694. super.start();
  695. invokeCallback(startProc, new IRubyObject[] {});
  696. }
  697. @Override
  698. public synchronized void stop() {
  699. invokeCallback(stopProc, new IRubyObject[] {});
  700. super.stop();
  701. }
  702. @Override
  703. public synchronized void destroy() {
  704. try {
  705. invokeCallback(destroyProc, new IRubyObject[] {});
  706. } finally {
  707. facade.destroy();
  708. final Ruby runtime = this.runtime;
  709. this.runtime = null;
  710. startProc = null;
  711. stopProc = null;
  712. destroyProc = null;
  713. paintProc = null;
  714. priorGraphics = null;
  715. wrappedGraphics = null;
  716. runtime.tearDown();
  717. super.destroy();
  718. }
  719. }
  720. @Override
  721. public void update(Graphics g) {
  722. paint(g);
  723. }
  724. @Override
  725. public synchronized void paint(Graphics g) {
  726. if (doubleBuffered) {
  727. paintBuffered(g);
  728. } else {
  729. paintUnbuffered(g);
  730. }
  731. }
  732. private synchronized void paintBuffered(Graphics g) {
  733. do {
  734. GraphicsConfiguration config = getGraphicsConfiguration();
  735. int width = getWidth();
  736. int height = getHeight();
  737. if (backBuffer == null || width != backBuffer.getWidth() || height != backBuffer.getHeight() || backBuffer.validate(config) == VolatileImage.IMAGE_INCOMPATIBLE) {
  738. if (backBuffer != null) {
  739. backBufferGraphics.dispose();
  740. backBufferGraphics = null;
  741. backBuffer.flush();
  742. backBuffer = null;
  743. }
  744. backBuffer = config.createCompatibleVolatileImage(width, height);
  745. backBufferGraphics = backBuffer.createGraphics();
  746. }
  747. backBufferGraphics.setClip(g.getClip());
  748. paintUnbuffered(backBufferGraphics);
  749. g.drawImage(backBuffer, 0, 0, this);
  750. } while (backBuffer.contentsLost());
  751. }
  752. private synchronized void paintUnbuffered(Graphics g) {
  753. if (backgroundColor != null) {
  754. g.setColor(backgroundColor);
  755. g.fillRect(0, 0, getWidth(), getHeight());
  756. }
  757. if (paintProc != null) {
  758. if (priorGraphics != g) {
  759. wrappedGraphics = JavaUtil.convertJavaToUsableRubyObject(runtime, g);
  760. priorGraphics = g;
  761. }
  762. ThreadContext context = runtime.getCurrentContext();
  763. paintProc.call(context, new IRubyObject[] {wrappedGraphics});
  764. }
  765. super.paint(g);
  766. }
  767. private static class TrivialFacade implements Facade {
  768. public TrivialFacade() {}
  769. public InputStream getInputStream() { return System.in; }
  770. public PrintStream getOutputStream() { return System.out; }
  771. public PrintStream getErrorStream() { return System.err; }
  772. public void attach(Ruby runtime, Applet applet) {
  773. final IRubyObject wrappedApplet = JavaUtil.convertJavaToUsableRubyObject(runtime, applet);
  774. wrappedApplet.dataWrapStruct(applet);
  775. runtime.defineGlobalConstant("JRUBY_APPLET", wrappedApplet);
  776. wrappedApplet.getMetaClass().defineAnnotatedMethods(RubyMethods.class);
  777. }
  778. public void destroy() {}
  779. }
  780. private static class ConsoleFacade implements Facade {
  781. private JTextPane textPane;
  782. private JScrollPane scrollPane;
  783. private TextAreaReadline adaptor;
  784. private InputStream inputStream;
  785. private PrintStream outputStream;
  786. private PrintStream errorStream;
  787. public ConsoleFacade(String bannerText) {
  788. textPane = new JTextPane();
  789. textPane.setMargin(new Insets(4, 4, 0, 4));
  790. textPane.setCaretColor(new Color(0xa4, 0x00, 0x00));
  791. textPane.setBackground(new Color(0xf2, 0xf2, 0xf2));
  792. textPane.setForeground(new Color(0xa4, 0x00, 0x00));
  793. Font font = findFont("Monospaced", Font.PLAIN, 14,
  794. new String[] {"Monaco", "Andale Mono"});
  795. textPane.setFont(font);
  796. scrollPane = new JScrollPane(textPane);
  797. scrollPane.setDoubleBuffered(true);
  798. if ( bannerText != null ) {
  799. bannerText = " " + bannerText + " \n\n";
  800. }
  801. adaptor = new TextAreaReadline(textPane, bannerText);
  802. inputStream = adaptor.getInputStream();
  803. outputStream = new PrintStream(adaptor.getOutputStream());
  804. errorStream = new PrintStream(adaptor.getOutputStream());
  805. }
  806. public InputStream getInputStream() { return inputStream; }
  807. public PrintStream getOutputStream() { return outputStream; }
  808. public PrintStream getErrorStream() { return errorStream; }
  809. public void attach(Ruby runtime, Applet applet) {
  810. adaptor.hookIntoRuntime(runtime);
  811. applet.add(scrollPane);
  812. applet.validate();
  813. }
  814. public void destroy() {
  815. Container parent = scrollPane.getParent();
  816. adaptor.shutdown();
  817. if (parent != null) {
  818. parent.remove(scrollPane);
  819. }
  820. }
  821. private Font findFont(String otherwise, int style, int size, String[] families) {
  822. String[] fonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
  823. Arrays.sort(fonts);
  824. for (int i = 0; i < families.length; i++) {
  825. if (Arrays.binarySearch(fonts, families[i]) >= 0) {
  826. return new Font(families[i], style, size);
  827. }
  828. }
  829. return new Font(otherwise, style, size);
  830. }
  831. }
  832. }
  833. /***** BEGIN LICENSE BLOCK *****
  834. * Version: CPL 1.0/GPL 2.0/LGPL 2.1
  835. *
  836. * The contents of this file are subject to the Common Public
  837. * License Version 1.0 (the "License"); you may not use this file
  838. * except in compliance with the License. You may obtain a copy of
  839. * the License at http://www.eclipse.org/legal/cpl-v10.html
  840. *
  841. * Software distributed under the License is distributed on an "AS
  842. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  843. * implied. See the License for the specific language governing
  844. * rights and limitations under the License.
  845. *
  846. * Copyright (C) 2007 Ola Bini <ola@ologix.com>
  847. *
  848. * Alternatively, the contents of this file may be used under the terms of
  849. * either of the GNU General Public License Version 2 or later (the "GPL"),
  850. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  851. * in which case the provisions of the GPL or the LGPL are applicable instead
  852. * of those above. If you wish to allow use of your version of this file only
  853. * under the terms of either the GPL or the LGPL, and not to allow others to
  854. * use your version of this file under the terms of the CPL, indicate your
  855. * decision by deleting the provisions above and replace them with the notice
  856. * and other provisions required by the GPL or the LGPL. If you do not delete
  857. * the provisions above, a recipient may use your version of this file under
  858. * the terms of any one of the CPL, the GPL or the LGPL.
  859. ***** END LICENSE BLOCK *****/
  860. package org.jruby;
  861. import java.io.BufferedWriter;
  862. import java.io.OutputStreamWriter;
  863. import java.net.InetAddress;
  864. import java.net.Socket;
  865. /**
  866. * @author <a href="mailto:ola.bini@ki.se">Ola Bini</a>
  867. */
  868. public class JRubyClient extends JRubyService {
  869. public JRubyClient(String[] args) throws Exception {
  870. Configuration conf = new Configuration(args[0]);
  871. if(conf.isDebug()) {
  872. System.err.println("Starting client with port " + conf.getPort() + ", key " + conf.getKey() + " and command " + conf.getCommand());
  873. }
  874. Socket socket = new Socket(InetAddress.getLocalHost(), conf.getPort());
  875. BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
  876. if(conf.terminate()) {
  877. writer.write(CMD_TERM + " " + conf.getKey() + "\n");
  878. } else if(conf.noMore()) {
  879. writer.write(CMD_NO_MORE + " " + conf.getKey() + "\n");
  880. } else {
  881. writer.write(CMD_START + " " + conf.getKey() + " " + conf.getCommand() + "\n");
  882. }
  883. writer.flush();
  884. writer.close();
  885. socket.close();
  886. }
  887. public static void main(String[] args) throws Exception {
  888. new JRubyClient(args);
  889. }
  890. }// JRubyClient
  891. /*
  892. ***** BEGIN LICENSE BLOCK *****
  893. * Version: CPL 1.0/GPL 2.0/LGPL 2.1
  894. *
  895. * The contents of this file are subject to the Common Public
  896. * License Version 1.0 (the "License"); you may not use this file
  897. * except in compliance with the License. You may obtain a copy of
  898. * the License at http://www.eclipse.org/legal/cpl-v10.html
  899. *
  900. * Software distributed under the License is distributed on an "AS
  901. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  902. * implied. See the License for the specific language governing
  903. * rights and limitations under the License.
  904. *
  905. * Copyright (C) 2007 Ola Bini <ola@ologix.com>
  906. *
  907. * Alternatively, the contents of this file may be used under the terms of
  908. * either of the GNU General Public License Version 2 or later (the "GPL"),
  909. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  910. * in which case the provisions of the GPL or the LGPL are applicable instead
  911. * of those above. If you wish to allow use of your version of this file only
  912. * under the terms of either the GPL or the LGPL, and not to allow others to
  913. * use your version of this file under the terms of the CPL, indicate your
  914. * decision by deleting the provisions above and replace them with the notice
  915. * and other provisions required by the GPL or the LGPL. If you do not delete
  916. * the provisions above, a recipient may use your version of this file under
  917. * the terms of any one of the CPL, the GPL or the LGPL.
  918. ***** END LICENSE BLOCK *****/
  919. package org.jruby;
  920. import java.io.BufferedReader;
  921. import java.io.InputStreamReader;
  922. import java.net.InetAddress;
  923. import java.net.InetSocketAddress;
  924. import java.net.ServerSocket;
  925. import java.net.Socket;
  926. import java.util.List;
  927. import java.util.ArrayList;
  928. /**
  929. * @author <a href="mailto:ola.bini@ki.se">Ola Bini</a>
  930. */
  931. public class JRubyServer extends JRubyService {
  932. private Configuration conf;
  933. private boolean stillStarting = true;
  934. private JRubyServer(String[] args) throws Exception {
  935. conf = new Configuration(args[0]);
  936. if(conf.isDebug()) {
  937. System.err.println("Starting server with port " + conf.getPort() + " and key " + conf.getKey());
  938. }
  939. ServerSocket server = new ServerSocket();
  940. server.bind(new InetSocketAddress(InetAddress.getLocalHost(),conf.getPort()));
  941. while(true) {
  942. Thread t1 = new Thread(new Handler(server.accept()));
  943. t1.setDaemon(true);
  944. t1.start();
  945. }
  946. }
  947. private class Handler implements Runnable {
  948. private Socket socket;
  949. public Handler(Socket socket) {
  950. this.socket = socket;
  951. }
  952. public void run() {
  953. try {
  954. BufferedReader rr = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
  955. String command = rr.readLine();
  956. rr.close();
  957. this.socket.close();
  958. this.socket = null;
  959. if(conf.isDebug()) {
  960. System.err.println("Got command: " + command);
  961. }
  962. String[] cmds = command.split(" ", 3);
  963. if(cmds[1].equals(conf.getKey())) {
  964. if(cmds[0].equals(CMD_TERM)) {
  965. if(conf.isDebug()) {
  966. System.err.println("Terminating hard");
  967. }
  968. System.exit(0);
  969. } else if(cmds[0].equals(CMD_NO_MORE)) {
  970. if(conf.isDebug()) {
  971. System.err.println("Accepting no more START");
  972. }
  973. stillStarting = false;
  974. } else if(cmds[0].equals(CMD_START)) {
  975. if(stillStarting) {
  976. if(conf.isDebug()) {
  977. System.err.println("Doing START on command " + cmds[2]);
  978. }
  979. new Main().run(intoCommandArguments(cmds[2].trim()));
  980. } else {
  981. if(conf.isDebug()) {
  982. System.err.println("Not doing START anymore, invalid command");
  983. }
  984. }
  985. } else {
  986. if(conf.isDebug()) {
  987. System.err.println("Unrecognized command");
  988. }
  989. }
  990. } else {
  991. if(conf.isDebug()) {
  992. System.err.println("Invalid key");
  993. }
  994. }
  995. } catch(Exception e) {}
  996. }
  997. }
  998. protected static String[] intoCommandArguments(String str) {
  999. List<String> args = new ArrayList<String>();
  1000. boolean inSingle = false;
  1001. int contentStart = -1;
  1002. for(int i=0,j=str.length();i<j;i++) {
  1003. if(str.charAt(i) == ' ' && !inSingle && contentStart != -1) {
  1004. args.add(str.substring(contentStart,i));
  1005. contentStart = -1;
  1006. continue;
  1007. }
  1008. if(str.charAt(i) == ' ') {
  1009. continue;
  1010. }
  1011. if(str.charAt(i) == '\'' && !inSingle) {
  1012. inSingle = true;
  1013. contentStart = i+1;
  1014. continue;
  1015. }
  1016. if(str.charAt(i) == '\'') {
  1017. inSingle = false;
  1018. args.add(str.substring(contentStart,i));
  1019. contentStart = -1;
  1020. continue;
  1021. }
  1022. if(contentStart == -1) {
  1023. contentStart = i;
  1024. }
  1025. }
  1026. if(contentStart != -1) {
  1027. args.add(str.substring(contentStart));
  1028. }
  1029. return (String[])args.toArray(new String[0]);
  1030. }
  1031. public static void main(String[] args) throws Exception {
  1032. new JRubyServer(args);
  1033. }
  1034. }// JRubyServer
  1035. /***** BEGIN LICENSE BLOCK *****
  1036. * Version: CPL 1.0/GPL 2.0/LGPL 2.1
  1037. *
  1038. * The contents of this file are subject to the Common Public
  1039. * License Version 1.0 (the "License"); you may not use this file
  1040. * except in compliance with the License. You may obtain a copy of
  1041. * the License at http://www.eclipse.org/legal/cpl-v10.html
  1042. *
  1043. * Software distributed under the License is distributed on an "AS
  1044. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  1045. * implied. See the License for the specific language governing
  1046. * rights and limitations under the License.
  1047. *
  1048. * Copyright (C) 2007 Ola Bini <ola@ologix.com>
  1049. *
  1050. * Alternatively, the contents of this file may be used under the terms of
  1051. * either of the GNU General Public License Version 2 or later (the "GPL"),
  1052. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  1053. * in which case the provisions of the GPL or the LGPL are applicable instead
  1054. * of those above. If you wish to allow use of your version of this file only
  1055. * under the terms of either the GPL or the LGPL, and not to allow others to
  1056. * use your version of this file under the terms of the CPL, indicate your
  1057. * decision by deleting the provisions above and replace them with the notice
  1058. * and other provisions required by the GPL or the LGPL. If you do not delete
  1059. * the provisions above, a recipient may use your version of this file under
  1060. * the terms of any one of the CPL, the GPL or the LGPL.
  1061. ***** END LICENSE BLOCK *****/
  1062. package org.jruby;
  1063. /**
  1064. * @author <a href="mailto:ola.bini@ki.se">Ola Bini</a>
  1065. */
  1066. public abstract class JRubyService {
  1067. protected static class Configuration {
  1068. private final static int DEFAULT_PORT = 19222;
  1069. private String key;
  1070. private int port = DEFAULT_PORT;
  1071. private boolean terminate;
  1072. private boolean noMore;
  1073. private boolean debug;
  1074. private String command;
  1075. public Configuration(String args) {
  1076. int i=0;
  1077. int stop;
  1078. loop: for(int j=args.length();i<j;i++) {
  1079. if(args.charAt(i) == '-' && i+1 < j) {
  1080. switch(args.charAt(++i)) {
  1081. case 'k':
  1082. stop = args.indexOf(" ", (++i) + 1);
  1083. if(stop == -1) {
  1084. stop = args.length();
  1085. }
  1086. key = args.substring(i, stop).trim();
  1087. i = stop;
  1088. break;
  1089. case 'p':
  1090. stop = args.indexOf(" ", (++i) + 1);
  1091. if(stop == -1) {
  1092. stop = args.length();
  1093. }
  1094. port = Integer.parseInt(args.substring(i, stop).trim());
  1095. i = stop;
  1096. break;
  1097. case 't':
  1098. terminate = true;
  1099. i++;
  1100. break;
  1101. case 'n':
  1102. noMore = true;
  1103. i++;
  1104. break;
  1105. case 'd':
  1106. debug = true;
  1107. i++;
  1108. break;
  1109. case '-': // handle everything after -- as arguments to the jruby process
  1110. i++;
  1111. break loop;
  1112. default:
  1113. i--;
  1114. break loop;
  1115. }
  1116. } else if(args.charAt(i) != ' ') {
  1117. break loop;
  1118. }
  1119. }
  1120. if(i<args.length()) {
  1121. command = args.substring(i).trim();
  1122. }
  1123. }
  1124. public String getKey() {
  1125. return key;
  1126. }
  1127. public int getPort() {
  1128. return port;
  1129. }
  1130. public boolean terminate() {
  1131. return terminate;
  1132. }
  1133. public boolean noMore() {
  1134. return noMore;
  1135. }
  1136. public boolean isDebug() {
  1137. return debug;
  1138. }
  1139. public String getCommand() {
  1140. return command;
  1141. }
  1142. }
  1143. public static final String CMD_START = "START";
  1144. public static final String CMD_NO_MORE = "NO_MORE";
  1145. public static final String CMD_TERM = "TERM";
  1146. }// JRubyService
  1147. /*
  1148. ***** BEGIN LICENSE BLOCK *****
  1149. * Version: CPL 1.0/GPL 2.0/LGPL 2.1
  1150. *
  1151. * The contents of this file are subject to the Common Public
  1152. * License Version 1.0 (the "License"); you may not use this file
  1153. * except in compliance with the License. You may obtain a copy of
  1154. * the License at http://www.eclipse.org/legal/cpl-v10.html
  1155. *
  1156. * Software distributed under the License is distributed on an "AS
  1157. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  1158. * implied. See the License for the specific language governing
  1159. * rights and limitations under the License.
  1160. *
  1161. * Copyright (C) 2001 Alan Moore <alan_moore@gmx.net>
  1162. * Copyright (C) 2001-2002 Benoit Cerrina <b.cerrina@wanadoo.fr>
  1163. * Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
  1164. * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
  1165. * Copyright (C) 2004 Thomas E Enebo <enebo@acm.org>
  1166. * Copyright (C) 2004-2006 Charles O Nutter <headius@headius.com>
  1167. * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
  1168. * Copyright (C) 2005 Kiel Hodges <jruby-devel@selfsosoft.com>
  1169. * Copyright (C) 2005 Jason Voegele <jason@jvoegele.com>
  1170. * Copyright (C) 2005 Tim Azzopardi <tim@tigerfive.com>
  1171. *
  1172. * Alternatively, the contents of this file may be used under the terms of
  1173. * either of the GNU General Public License Version 2 or later (the "GPL"),
  1174. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  1175. * in which case the provisions of the GPL or the LGPL are applicable instead
  1176. * of those above. If you wish to allow use of your version of this file only
  1177. * under the terms of either the GPL or the LGPL, and not to allow others to
  1178. * use your version of this file under the terms of the CPL, indicate your
  1179. * decision by deleting the provisions above and replace them with the notice
  1180. * and other provisions required by the GPL or the LGPL. If you do not delete
  1181. * the provisions above, a recipient may use your version of this file under
  1182. * the terms of any one of the CPL, the GPL or the LGPL.
  1183. ***** END LICENSE BLOCK *****/
  1184. package org.jruby;
  1185. import java.io.InputStream;
  1186. import java.io.PrintStream;
  1187. import org.jruby.exceptions.MainExitException;
  1188. import org.jruby.exceptions.RaiseException;
  1189. import org.jruby.exceptions.ThreadKill;
  1190. import org.jruby.runtime.ThreadContext;
  1191. import org.jruby.runtime.builtin.IRubyObject;
  1192. import org.jruby.util.SafePropertyAccessor;
  1193. import org.jruby.util.SimpleSampler;
  1194. /**
  1195. * Class used to launch the interpreter.
  1196. * This is the main class as defined in the jruby.mf manifest.
  1197. * It is very basic and does not support yet the same array of switches
  1198. * as the C interpreter.
  1199. * Usage: java -jar jruby.jar [switches] [rubyfile.rb] [arguments]
  1200. * -e 'command' one line of script. Several -e's allowed. Omit [programfile]
  1201. * @author jpetersen
  1202. */
  1203. public class Main {
  1204. private boolean hasPrintedUsage = false;
  1205. private final RubyInstanceConfig config;
  1206. public Main(RubyInstanceConfig config) {
  1207. this.config = config;
  1208. }
  1209. public Main(final InputStream in, final PrintStream out, final PrintStream err) {
  1210. this(new RubyInstanceConfig(){{
  1211. setInput(in);
  1212. setOutput(out);
  1213. setError(err);
  1214. }});
  1215. }
  1216. public Main() {
  1217. this(new RubyInstanceConfig());
  1218. }
  1219. public static void main(String[] args) {
  1220. Main main = new Main();
  1221. try {
  1222. int status = main.run(args);
  1223. if (status != 0) {
  1224. System.exit(status);
  1225. }
  1226. } catch (RaiseException re) {
  1227. throw re;
  1228. } catch (Throwable t) {
  1229. // print out as a nice Ruby backtrace
  1230. System.err.println(ThreadContext.createRawBacktraceStringFromThrowable(t));
  1231. System.exit(1);
  1232. }
  1233. }
  1234. public int run(String[] args) {
  1235. try {
  1236. config.processArguments(args);
  1237. return run();
  1238. } catch (MainExitException mee) {
  1239. if (!mee.isAborted()) {
  1240. config.getOutput().println(mee.getMessage());
  1241. if (mee.isUsageError()) {
  1242. printUsage();
  1243. }
  1244. }
  1245. return mee.getStatus();
  1246. } catch (OutOfMemoryError oome) {
  1247. // produce a nicer error since Rubyists aren't used to seeing this
  1248. System.gc();
  1249. String memoryMax = SafePropertyAccessor.getProperty("jruby.memory.max");
  1250. String message = "";
  1251. if (memoryMax != null) {
  1252. message = " of " + memoryMax;
  1253. }
  1254. System.err.println("Error: Your application used more memory than the safety cap" + message + ".");
  1255. System.err.println("Specify -J-Xmx####m to increase it (#### = cap size in MB).");
  1256. if (config.getVerbose()) {
  1257. System.err.println("Exception trace follows:");
  1258. oome.printStackTrace();
  1259. } else {
  1260. System.err.println("Specify -w for full OutOfMemoryError stack trace");
  1261. }
  1262. return 1;
  1263. } catch (StackOverflowError soe) {
  1264. // produce a nicer error since Rubyists aren't used to seeing this
  1265. System.gc();
  1266. String stackMax = SafePropertyAccessor.getProperty("jruby.stack.max");
  1267. String message = "";
  1268. if (stackMax != null) {
  1269. message = " of " + stackMax;
  1270. }
  1271. System.err.println("Error: Your application used more stack memory than the safety cap" + message + ".");
  1272. System.err.println("Specify -J-Xss####k to increase it (#### = cap size in KB).");
  1273. if (config.getVerbose()) {
  1274. System.err.println("Exception trace follows:");
  1275. soe.printStackTrace();
  1276. } else {
  1277. System.err.println("Specify -w for full StackOverflowError stack trace");
  1278. }
  1279. return 1;
  1280. } catch (UnsupportedClassVersionError ucve) {
  1281. System.err.println("Error: Some library (perhaps JRuby) was built with a later JVM version.");
  1282. System.err.println("Please use libraries built with the version you intend to use or an earlier one.");
  1283. if (config.getVerbose()) {
  1284. System.err.println("Exception trace follows:");
  1285. ucve.printStackTrace();
  1286. } else {
  1287. System.err.println("Specify -w for full UnsupportedClassVersionError stack trace");
  1288. }
  1289. return 1;
  1290. } catch (ThreadKill kill) {
  1291. return 0;
  1292. }
  1293. }
  1294. public int run() {
  1295. if (config.isShowVersion()) {
  1296. showVersion();
  1297. }
  1298. if (config.isShowCopyright()) {
  1299. showCopyright();
  1300. }
  1301. if (!config.shouldRunInterpreter() ) {
  1302. if (config.shouldPrintUsage()) {
  1303. printUsage();
  1304. }
  1305. if (config.shouldPrintProperties()) {
  1306. printProperties();
  1307. }
  1308. return 0;
  1309. }
  1310. InputStream in = config.getScriptSource();
  1311. String filename = config.displayedFileName();
  1312. Ruby runtime = Ruby.newInstance(config);
  1313. // set thread context JRuby classloader here, for the main thread
  1314. try {
  1315. Thread.currentThread().setContextClassLoader(runtime.getJRubyClassLoader());
  1316. } catch (SecurityException se) {
  1317. // can't set TC classloader
  1318. if (runtime.getInstanceConfig().isVerbose()) {
  1319. System.err.println("WARNING: Security restrictions disallowed setting context classloader for main thread.");
  1320. }
  1321. }
  1322. if (in == null) {
  1323. // no script to run, return success below
  1324. } else if (config.isShouldCheckSyntax()) {
  1325. runtime.parseFromMain(in, filename);
  1326. config.getOutput().println("Syntax OK");
  1327. } else {
  1328. long now = -1;
  1329. try {
  1330. if (config.isBenchmarking()) {
  1331. now = System.currentTimeMillis();
  1332. }
  1333. if (config.isSamplingEnabled()) {
  1334. SimpleSampler.startSampleThread();
  1335. }
  1336. try {
  1337. runtime.runFromMain(in, filename);
  1338. } finally {
  1339. runtime.tearDown();
  1340. if (config.isBenchmarking()) {
  1341. config.getOutput().println("Runtime: " + (System.currentTimeMillis() - now) + " ms");
  1342. }
  1343. if (config.isSamplingEnabled()) {
  1344. org.jruby.util.SimpleSampler.report();
  1345. }
  1346. }
  1347. } catch (RaiseException rj) {
  1348. RubyException raisedException = rj.getException();
  1349. if (runtime.getSystemExit().isInstance(raisedException)) {
  1350. IRubyObject status = raisedException.callMethod(runtime.getCurrentContext(), "status");
  1351. if (status != null && !status.isNil()) {
  1352. return RubyNumeric.fix2int(status);
  1353. }
  1354. } else {
  1355. runtime.printError(raisedException);
  1356. return 1;
  1357. }
  1358. }
  1359. }
  1360. return 0;
  1361. }
  1362. private void showVersion() {
  1363. config.getOutput().print(config.getVersionString());
  1364. }
  1365. private void showCopyright() {
  1366. config.getOutput().print(config.getCopyrightString());
  1367. }
  1368. public void printUsage() {
  1369. if (!hasPrintedUsage) {
  1370. config.getOutput().print(config.getBasicUsageHelp());
  1371. hasPrintedUsage = true;
  1372. }
  1373. }
  1374. public void printProperties() {
  1375. config.getOutput().print(config.getPropertyHelp());
  1376. }
  1377. }
  1378. /***** BEGIN LICENSE BLOCK *****
  1379. * Version: CPL 1.0/GPL 2.0/LGPL 2.1
  1380. *
  1381. * The contents of this file are subject to the Common Public
  1382. * License Version 1.0 (the "License"); you may not use this file
  1383. * except in compliance with the License. You may obtain a copy of
  1384. * the License at http://www.eclipse.org/legal/cpl-v10.html
  1385. *
  1386. * Software distributed under the License is distributed on an "AS
  1387. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  1388. * implied. See the License for the specific language governing
  1389. * rights and limitations under the License.
  1390. *
  1391. * Copyright (C) 2002-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
  1392. * Copyright (C) 2004-2006 Thomas E Enebo <enebo@acm.org>
  1393. * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
  1394. *
  1395. * Alternatively, the contents of this file may be used under the terms of
  1396. * either of the GNU General Public License Version 2 or later (the "GPL"),
  1397. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  1398. * in which case the provisions of the GPL or the LGPL are applicable instead
  1399. * of those above. If you wish to allow use of your version of this file only
  1400. * under the terms of either the GPL or the LGPL, and not to allow others to
  1401. * use your version of this file under the terms of the CPL, indicate your
  1402. * decision by deleting the provisions above and replace them with the notice
  1403. * and other provisions required by the GPL or the LGPL. If you do not delete
  1404. * the provisions above, a recipient may use your version of this file under
  1405. * the terms of any one of the CPL, the GPL or the LGPL.
  1406. ***** END LICENSE BLOCK *****/
  1407. package org.jruby;
  1408. import java.lang.ref.SoftReference;
  1409. import org.jruby.runtime.builtin.IRubyObject;
  1410. public final class MetaClass extends RubyClass {
  1411. private SoftReference<IRubyObject> attached = new SoftReference<IRubyObject>(null);
  1412. /** NEWOBJ (in RubyObject#getSingletonClassClone())
  1413. *
  1414. */
  1415. public MetaClass(Ruby runtime) {
  1416. super(runtime, null, false);
  1417. }
  1418. /** rb_class_boot (for MetaClasses) (in makeMetaClass(RubyClass))
  1419. *
  1420. */
  1421. public MetaClass(Ruby runtime, RubyClass superClass) {
  1422. super(runtime, superClass, false);
  1423. index = superClass.index; // use same ClassIndex as metaclass, since we're technically still of that type
  1424. }
  1425. public boolean isSingleton() {
  1426. return true;
  1427. }
  1428. /**
  1429. * If an object uses an anonymous class 'class << obj', then this grabs the original
  1430. * metaclass and not the one that get injected as a result of 'class << obj'.
  1431. */
  1432. public RubyClass getRealClass() {
  1433. return superClass.getRealClass();
  1434. }
  1435. public final IRubyObject allocate(){
  1436. throw getRuntime().newTypeError("can't create instance of virtual class");
  1437. }
  1438. public IRubyObject getAttached() {
  1439. return attached.get();
  1440. }
  1441. public void setAttached(IRubyObject attached) {
  1442. this.attached = new SoftReference<IRubyObject>(attached);
  1443. }
  1444. }
  1445. /***** BEGIN LICENSE BLOCK *****
  1446. * Version: CPL 1.0/GPL 2.0/LGPL 2.1
  1447. *
  1448. * The contents of this file are subject to the Common Public
  1449. * License Version 1.0 (the "License"); you may not use this file
  1450. * except in compliance with the License. You may obtain a copy of
  1451. * the License at http://www.eclipse.org/legal/cpl-v10.html
  1452. *
  1453. * Software distributed under the License is distributed on an "AS
  1454. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  1455. * implied. See the License for the specific language governing
  1456. * rights and limitations under the License.
  1457. *
  1458. * Copyright (C) 2005 David Corbin <dcorbin@users.sourceforge.net>
  1459. *
  1460. * Alternatively, the contents of this file may be used under the terms of
  1461. * either of the GNU General Public License Version 2 or later (the "GPL"),
  1462. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  1463. * in which case the provisions of the GPL or the LGPL are applicable instead
  1464. * of those above. If you wish to allow use of your version of this file only
  1465. * under the terms of either the GPL or the LGPL, and not to allow others to
  1466. * use your version of this file under the terms of the CPL, indicate your
  1467. * decision by deleting the provisions above and replace them with the notice
  1468. * and other provisions required by the GPL or the LGPL. If you do not delete
  1469. * the provisions above, a recipient may use your version of this file under
  1470. * the terms of any one of the CPL, the GPL or the LGPL.
  1471. ***** END LICENSE BLOCK *****/
  1472. package org.jruby;
  1473. import java.io.PrintStream;
  1474. import org.jruby.anno.JRubyClass;
  1475. import org.jruby.anno.JRubyMethod;
  1476. import org.jruby.javasupport.Java;
  1477. import org.jruby.javasupport.JavaObject;
  1478. import org.jruby.runtime.Block;
  1479. import org.jruby.runtime.ObjectAllocator;
  1480. import org.jruby.runtime.builtin.IRubyObject;
  1481. @JRubyClass(name = "NativeException", parent = "RuntimeError")
  1482. public class NativeException extends RubyException {
  1483. private final Throwable cause;
  1484. public static final String CLASS_NAME = "NativeException";
  1485. private final Ruby runtime;
  1486. public NativeException(Ruby runtime, RubyClass rubyClass, Throwable cause) {
  1487. super(runtime, rubyClass, cause.getClass().getName() + ": " + cause.getMessage());
  1488. this.runtime = runtime;
  1489. this.cause = cause;
  1490. }
  1491. public static RubyClass createClass(Ruby runtime, RubyClass baseClass) {
  1492. // FIXME: If NativeException is expected to be used from Ruby code, it should provide
  1493. // a real allocator to be used. Otherwise Class.new will fail, as will marshalling. JRUBY-415
  1494. RubyClass exceptionClass = runtime.defineClass(CLASS_NAME, baseClass, ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);
  1495. exceptionClass.defineAnnotatedMethods(NativeException.class);
  1496. return exceptionClass;
  1497. }
  1498. @JRubyMethod(frame = true)
  1499. public IRubyObject cause(Block unusedBlock) {
  1500. return Java.wrap(getRuntime(), JavaObject.wrap(getRuntime(), cause));
  1501. }
  1502. public IRubyObject backtrace() {
  1503. IRubyObject rubyTrace = super.backtrace();
  1504. if (rubyTrace.isNil()) {
  1505. return rubyTrace;
  1506. }
  1507. RubyArray array = (RubyArray) rubyTrace.dup();
  1508. StackTraceElement[] stackTrace = cause.getStackTrace();
  1509. for (int i = stackTrace.length - 1; i >= 0; i--) {
  1510. StackTraceElement element = stackTrace[i];
  1511. String className = element.getClassName();
  1512. String line = null;
  1513. if (element.getFileName() == null) {
  1514. line = className + ":" + element.getLineNumber() + ":in `" + element.getMethodName() + "'";
  1515. } else {
  1516. int index = className.lastIndexOf(".");
  1517. String packageName = null;
  1518. if (index == -1) {
  1519. packageName = "";
  1520. } else {
  1521. packageName = className.substring(0, index) + "/";
  1522. }
  1523. line = packageName.replace(".", "/") + element.getFileName() + ":" + element.getLineNumber() + ":in `" + element.getMethodName() + "'";
  1524. }
  1525. RubyString string = runtime.newString(line);
  1526. array.unshift(string);
  1527. }
  1528. return array;
  1529. }
  1530. public void printBacktrace(PrintStream errorStream) {
  1531. super.printBacktrace(errorStream);
  1532. errorStream.println("Complete Java stackTrace");
  1533. cause.printStackTrace(errorStream);
  1534. }
  1535. public Throwable getCause() {
  1536. return cause;
  1537. }
  1538. }
  1539. /***** BEGIN LICENSE BLOCK *****
  1540. * Version: CPL 1.0/GPL 2.0/LGPL 2.1
  1541. *
  1542. * The contents of this file are subject to the Common Public
  1543. * License Version 1.0 (the "License"); you may not use this file
  1544. * except in compliance with the License. You may obtain a copy of
  1545. * the License at http://www.eclipse.org/legal/cpl-v10.html
  1546. *
  1547. * Software distributed under the License is distributed on an "AS
  1548. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  1549. * implied. See the License for the specific language governing
  1550. * rights and limitations under the License.
  1551. *
  1552. * Copyright (C) 2006 Ola Bini <ola@ologix.com>
  1553. *
  1554. * Alternatively, the contents of this file may be used under the terms of
  1555. * either of the GNU General Public License Version 2 or later (the "GPL"),
  1556. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  1557. * in which case the provisions of the GPL or the LGPL are applicable instead
  1558. * of those above. If you wish to allow use of your version of this file only
  1559. * under the terms of either the GPL or the LGPL, and not to allow others to
  1560. * use your version of this file under the terms of the CPL, indicate your
  1561. * decision by deleting the provisions above and replace them with the notice
  1562. * and other provisions required by the GPL or the LGPL. If you do not delete
  1563. * the provisions above, a recipient may use your version of this file under
  1564. * the terms of any one of the CPL, the GPL or the LGPL.
  1565. ***** END LICENSE BLOCK *****/
  1566. package org.jruby;
  1567. /**
  1568. * @author <a href="mailto:ola.bini@ki.se">Ola Bini</a>
  1569. */
  1570. public interface Profile {
  1571. Profile ALL = new Profile() {
  1572. public boolean allowBuiltin(String name) { return true; }
  1573. public boolean allowClass(String name) { return true; }
  1574. public boolean allowModule(String name) { return true; }
  1575. public boolean allowLoad(String name) { return true; }
  1576. public boolean allowRequire(String name) { return true; }
  1577. };
  1578. Profile DEBUG_ALLOW = new Profile() {
  1579. public boolean allowBuiltin(String name) { System.err.println("allowBuiltin("+name+")"); return true; }
  1580. public boolean allowClass(String name) { System.err.println("allowClass("+name+")"); return true; }
  1581. public boolean allowModule(String name) { System.err.println("allowModule("+name+")"); return true; }
  1582. public boolean allowLoad(String name) { System.err.println("allowLoad("+name+")"); return true; }
  1583. public boolean allowRequire(String name) { System.err.println("allowRequire("+name+")"); return true; }
  1584. };
  1585. Profile NO_FILE_CLASS = new Profile() {
  1586. public boolean allowBuiltin(String name) { return true; }
  1587. public boolean allowClass(String name) { return !name.equals("File"); }
  1588. public boolean allowModule(String name) { return true; }
  1589. public boolean allowLoad(String name) { return true; }
  1590. public boolean allowRequire(String name) { return true; }
  1591. };
  1592. Profile ANY = ALL;
  1593. Profile DEFAULT = ALL;
  1594. boolean allowBuiltin(String name);
  1595. boolean allowClass(String name);
  1596. boolean allowModule(String name);
  1597. boolean allowLoad(String name);
  1598. boolean allowRequire(String name);
  1599. }// Profile
  1600. /*
  1601. **** BEGIN LICENSE BLOCK *****
  1602. * Version: CPL 1.0/GPL 2.0/LGPL 2.1
  1603. *
  1604. * The contents of this file are subject to the Common Public
  1605. * License Version 1.0 (the "License"); you may not use this file
  1606. * except in compliance with the License. You may obtain a copy of
  1607. * the License at http://www.eclipse.org/legal/cpl-v10.html
  1608. *
  1609. * Software distributed under the License is distributed on an "AS
  1610. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  1611. * implied. See the License for the specific language governing
  1612. * rights and limitations under the License.
  1613. *
  1614. * Copyright (C) 2001 Chad Fowler <chadfowler@chadfowler.com>
  1615. * Copyright (C) 2001 Alan Moore <alan_moore@gmx.net>
  1616. * Copyright (C) 2001-2002 Benoit Cerrina <b.cerrina@wanadoo.fr>
  1617. * Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
  1618. * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
  1619. * Copyright (C) 2004 Thomas E Enebo <enebo@acm.org>
  1620. * Copyright (C) 2004-2005 Charles O Nutter <headius@headius.com>
  1621. * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
  1622. * Copyright (C) 2006 Miguel Covarrubias <mlcovarrubias@gmail.com>
  1623. * Copyright (C) 2006 Michael Studman <codehaus@michaelstudman.com>
  1624. * Copyright (C) 2006 Ola Bini <ola@ologix.com>
  1625. * Copyright (C) 2007 Nick Sieger <nicksieger@gmail.com>
  1626. *
  1627. * Alternatively, the contents of this file may be used under the terms of
  1628. * either of the GNU General Public License Version 2 or later (the "GPL"),
  1629. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  1630. * in which case the provisions of the GPL or the LGPL are applicable instead
  1631. * of those above. If you wish to allow use of your version of this file only
  1632. * under the terms of either the GPL or the LGPL, and not to allow others to
  1633. * use your version of this file under the terms of the CPL, indicate your
  1634. * decision by deleting the provisions above and replace them with the notice
  1635. * and other provisions required by the GPL or the LGPL. If you do not delete
  1636. * the provisions above, a recipient may use your version of this file under
  1637. * the terms of any one of the CPL, the GPL or the LGPL.
  1638. ***** END LICENSE BLOCK *****/
  1639. package org.jruby;
  1640. import java.io.ByteArrayInputStream;
  1641. import java.io.File;
  1642. import java.io.FileDescriptor;
  1643. import java.io.IOException;
  1644. import java.io.InputStream;
  1645. import java.io.PrintStream;
  1646. import java.io.UnsupportedEncodingException;
  1647. import java.lang.ref.WeakReference;
  1648. import java.lang.reflect.Field;
  1649. import java.util.ArrayList;
  1650. import java.util.Collections;
  1651. import java.util.HashMap;
  1652. import java.util.Hashtable;
  1653. import java.util.IdentityHashMap;
  1654. import java.util.Iterator;
  1655. import java.util.List;
  1656. import java.util.Map;
  1657. import java.util.Random;
  1658. import java.util.Set;
  1659. import java.util.Stack;
  1660. import java.util.Vector;
  1661. import java.util.WeakHashMap;
  1662. import java.util.concurrent.ConcurrentHashMap;
  1663. import java.util.concurrent.ExecutorService;
  1664. import java.util.concurrent.Executors;
  1665. import java.util.concurrent.SynchronousQueue;
  1666. import java.util.concurrent.ThreadFactory;
  1667. import java.util.concurrent.ThreadPoolExecutor;
  1668. import java.util.concurrent.TimeUnit;
  1669. import java.util.concurrent.atomic.AtomicInteger;
  1670. import org.joda.time.DateTimeZone;
  1671. import org.jruby.ast.Node;
  1672. import org.jruby.ast.executable.RubiniusRunner;
  1673. import org.jruby.ast.executable.Script;
  1674. import org.jruby.ast.executable.YARVCompiledRunner;
  1675. import org.jruby.common.RubyWarnings;
  1676. import org.jruby.common.IRubyWarnings.ID;
  1677. import org.jruby.compiler.ASTCompiler;
  1678. import org.jruby.compiler.ASTInspector;
  1679. import org.jruby.compiler.JITCompiler;
  1680. import org.jruby.compiler.NotCompilableException;
  1681. import org.jruby.compiler.impl.StandardASMCompiler;
  1682. import org.jruby.compiler.yarv.StandardYARVCompiler;
  1683. import org.jruby.exceptions.JumpException;
  1684. import org.jruby.exceptions.RaiseException;
  1685. import org.jruby.ext.JRubyPOSIXHandler;
  1686. import org.jruby.ext.LateLoadingLibrary;
  1687. import org.jruby.ext.posix.POSIX;
  1688. import org.jruby.ext.posix.POSIXFactory;
  1689. import org.jruby.internal.runtime.GlobalVariables;
  1690. import org.jruby.internal.runtime.ThreadService;
  1691. import org.jruby.internal.runtime.ValueAccessor;
  1692. import org.jruby.javasupport.JavaSupport;
  1693. import org.jruby.management.BeanManager;
  1694. import org.jruby.management.ClassCache;
  1695. import org.jruby.management.Config;
  1696. import org.jruby.parser.Parser;
  1697. import org.jruby.parser.ParserConfiguration;
  1698. import org.jruby.runtime.Binding;
  1699. import org.jruby.runtime.Block;
  1700. import org.jruby.runtime.CacheMap;
  1701. import org.jruby.runtime.CallSite;
  1702. import org.jruby.runtime.CallbackFactory;
  1703. import org.jruby.runtime.DynamicScope;
  1704. import org.jruby.runtime.EventHook;
  1705. import org.jruby.runtime.GlobalVariable;
  1706. import org.jruby.runtime.IAccessor;
  1707. import org.jruby.runtime.ObjectAllocator;
  1708. import org.jruby.runtime.ObjectSpace;
  1709. import org.jruby.runtime.RubyEvent;
  1710. import org.jruby.runtime.ThreadContext;
  1711. import org.jruby.runtime.builtin.IRubyObject;
  1712. import org.jruby.runtime.load.Library;
  1713. import org.jruby.runtime.load.LoadService;
  1714. import org.jruby.util.BuiltinScript;
  1715. import org.jruby.util.ByteList;
  1716. import org.jruby.util.IOInputStream;
  1717. import org.jruby.util.IOOutputStream;
  1718. import org.jruby.util.JRubyClassLoader;
  1719. import org.jruby.util.JavaNameMangler;
  1720. import org.jruby.util.KCode;
  1721. import org.jruby.util.SafePropertyAccessor;
  1722. import org.jruby.util.collections.WeakHashSet;
  1723. import org.jruby.util.io.ChannelDescriptor;
  1724. /**
  1725. * The Ruby object represents the top-level of a JRuby "instance" in a given VM.
  1726. * JRuby supports spawning multiple instances in the same JVM. Generally, objects
  1727. * created under these instances are tied to a given runtime, for such details
  1728. * as identity and type, because multiple Ruby instances means there are
  1729. * multiple instances of each class. This means that in multi-runtime mode
  1730. * (or really, multi-VM mode, where each JRuby instance is a ruby "VM"), objects
  1731. * generally can't be transported across runtimes without marshaling.
  1732. *
  1733. * This class roots everything that makes the JRuby runtime function, and
  1734. * provides a number of utility methods for constructing global types and
  1735. * accessing global runtime structures.
  1736. */
  1737. public final class Ruby {
  1738. /**
  1739. * Returns a new instance of the JRuby runtime configured with defaults.
  1740. *
  1741. * @return the JRuby runtime
  1742. * @see org.jruby.RubyInstanceConfig
  1743. */
  1744. public static Ruby newInstance() {
  1745. return newInstance(new RubyInstanceConfig());
  1746. }
  1747. /**
  1748. * Returns a new instance of the JRuby runtime configured as specified.
  1749. *
  1750. * @param config The instance configuration
  1751. * @return The JRuby runtime
  1752. * @see org.jruby.RubyInstanceConfig
  1753. */
  1754. public static Ruby newInstance(RubyInstanceConfig config) {
  1755. Ruby ruby = new Ruby(config);
  1756. ruby.init();
  1757. return ruby;
  1758. }
  1759. /**
  1760. * Returns a new instance of the JRuby runtime configured with the given
  1761. * input, output and error streams and otherwise default configuration
  1762. * (except where specified system properties alter defaults).
  1763. *
  1764. * @param in the custom input stream
  1765. * @param out the custom output stream
  1766. * @param err the custom error stream
  1767. * @return the JRuby runtime
  1768. * @see org.jruby.RubyInstanceConfig
  1769. */
  1770. public static Ruby newInstance(InputStream in, PrintStream out, PrintStream err) {
  1771. RubyInstanceConfig config = new RubyInstanceConfig();
  1772. config.setInput(in);
  1773. config.setOutput(out);
  1774. config.setError(err);
  1775. return newInstance(config);
  1776. }
  1777. /**
  1778. * Create and initialize a new JRuby runtime. The properties of the
  1779. * specified RubyInstanceConfig will be used to determine various JRuby
  1780. * runtime characteristics.
  1781. *
  1782. * @param config The configuration to use for the new instance
  1783. * @see org.jruby.RubyInstanceConfig
  1784. */
  1785. private Ruby(RubyInstanceConfig config) {
  1786. this.config = config;
  1787. this.threadService = new ThreadService(this);
  1788. if(config.isSamplingEnabled()) {
  1789. org.jruby.util.SimpleSampler.registerThreadContext(threadService.getCurrentContext());
  1790. }
  1791. this.in = config.getInput();
  1792. this.out = config.getOutput();
  1793. this.err = config.getError();
  1794. this.objectSpaceEnabled = config.isObjectSpaceEnabled();
  1795. this.profile = config.getProfile();
  1796. this.currentDirectory = config.getCurrentDirectory();
  1797. this.kcode = config.getKCode();
  1798. this.beanManager = new BeanManager(this, config.isManagementEnabled());
  1799. this.jitCompiler = new JITCompiler(this);
  1800. this.beanManager.register(new Config(this));
  1801. this.beanManager.register(new ClassCache(this));
  1802. this.cacheMap = new CacheMap(this);
  1803. }
  1804. /**
  1805. * Evaluates a script under the current scope (perhaps the top-level
  1806. * scope) and returns the result (generally the last value calculated).
  1807. * This version goes straight into the interpreter, bypassing compilation
  1808. * and runtime preparation typical to normal script runs.
  1809. *
  1810. * @param script The scriptlet to run
  1811. * @returns The result of the eval
  1812. */
  1813. public IRubyObject evalScriptlet(String script) {
  1814. ThreadContext context = getCurrentContext();
  1815. Node node = parseEval(script, "<script>", context.getCurrentScope(), 0);
  1816. try {
  1817. return node.interpret(this, context, context.getFrameSelf(), Block.NULL_BLOCK);
  1818. } catch (JumpException.ReturnJump rj) {
  1819. throw newLocalJumpError("return", (IRubyObject)rj.getValue(), "unexpected return");
  1820. } catch (JumpException.BreakJump bj) {
  1821. throw newLocalJumpError("break", (IRubyObject)bj.getValue(), "unexpected break");
  1822. } catch (JumpException.RedoJump rj) {
  1823. throw newLocalJumpError("redo", (IRubyObject)rj.getValue(), "unexpected redo");
  1824. }
  1825. }
  1826. /**
  1827. * Parse and execute the specified script
  1828. * This differs from the other methods in that it accepts a string-based script and
  1829. * parses and runs it as though it were loaded at a command-line. This is the preferred
  1830. * way to start up a new script when calling directly into the Ruby object (which is
  1831. * generally *dis*couraged.
  1832. *
  1833. * @param script The contents of the script to run as a normal, root script
  1834. * @return The last value of the script
  1835. */
  1836. public IRubyObject executeScript(String script, String filename) {
  1837. byte[] bytes;
  1838. try {
  1839. bytes = script.getBytes(KCode.NONE.getKCode());
  1840. } catch (UnsupportedEncodingException e) {
  1841. bytes = script.getBytes();
  1842. }
  1843. Node node = parseInline(new ByteArrayInputStream(bytes), filename, null);
  1844. ThreadContext context = getCurrentContext();
  1845. String oldFile = context.getFile();
  1846. int oldLine = context.getLine();
  1847. try {
  1848. context.setFile(node.getPosition().getFile());
  1849. context.setLine(node.getPosition().getStartLine());
  1850. return runNormally(node, false);
  1851. } finally {
  1852. context.setFile(oldFile);
  1853. context.setLine(oldLine);
  1854. }
  1855. }
  1856. /**
  1857. * Run the script contained in the specified input stream, using the
  1858. * specified filename as the name of the script being executed. The stream
  1859. * will be read fully before being parsed and executed. The given filename
  1860. * will be used for the ruby $PROGRAM_NAME and $0 global variables in this
  1861. * runtime.
  1862. *
  1863. * This method is intended to be called once per runtime, generally from
  1864. * Main or from main-like top-level entry points.
  1865. *
  1866. * As part of executing the script loaded from the input stream, various
  1867. * RubyInstanceConfig properties will be used to determine whether to
  1868. * compile the script before execution or run with various wrappers (for
  1869. * looping, printing, and so on, see jruby -help).
  1870. *
  1871. * @param inputStream The InputStream from which to read the script contents
  1872. * @param filename The filename to use when parsing, and for $PROGRAM_NAME
  1873. * and $0 ruby global variables.
  1874. */
  1875. public void runFromMain(InputStream inputStream, String filename) {
  1876. IAccessor d = new ValueAccessor(newString(filename));
  1877. getGlobalVariables().define("$PROGRAM_NAME", d);
  1878. getGlobalVariables().define("$0", d);
  1879. for (Iterator i = config.getOptionGlobals().entrySet().iterator(); i.hasNext();) {
  1880. Map.Entry entry = (Map.Entry) i.next();
  1881. Object value = entry.getValue();
  1882. IRubyObject varvalue;
  1883. if (value != null) {
  1884. varvalue = newString(value.toString());
  1885. } else {
  1886. varvalue = getTrue();
  1887. }
  1888. getGlobalVariables().set("$" + entry.getKey().toString(), varvalue);
  1889. }
  1890. if(config.isYARVEnabled()) {
  1891. if (config.isShowBytecode()) System.err.print("error: bytecode printing only works with JVM bytecode");
  1892. new YARVCompiledRunner(this, inputStream, filename).run();
  1893. } else if(config.isRubiniusEnabled()) {
  1894. if (config.isShowBytecode()) System.err.print("error: bytecode printing only works with JVM bytecode");
  1895. new RubiniusRunner(this, inputStream, filename).run();
  1896. } else {
  1897. Node scriptNode = parseFromMain(inputStream, filename);
  1898. ThreadContext context = getCurrentContext();
  1899. String oldFile = context.getFile();
  1900. int oldLine = context.getLine();
  1901. try {
  1902. context.setFile(scriptNode.getPosition().getFile());
  1903. context.setLine(scriptNode.getPosition().getStartLine());
  1904. if (config.isAssumePrinting() || config.isAssumeLoop()) {
  1905. runWithGetsLoop(scriptNode, config.isAssumePrinting(), config.isProcessLineEnds(),
  1906. config.isSplit(), config.isYARVCompileEnabled());
  1907. } else {
  1908. runNormally(scriptNode, config.isYARVCompileEnabled());
  1909. }
  1910. } finally {
  1911. context.setFile(oldFile);
  1912. context.setLine(oldLine);
  1913. }
  1914. }
  1915. }
  1916. /**
  1917. * Parse the script contained in the given input stream, using the given
  1918. * filename as the name of the script, and return the root Node. This
  1919. * is used to verify that the script syntax is valid, for jruby -c. The
  1920. * current scope (generally the top-level scope) is used as the parent
  1921. * scope for parsing.
  1922. *
  1923. * @param inputStream The input stream from which to read the script
  1924. * @param filename The filename to use for parsing
  1925. * @returns The root node of the parsed script
  1926. */
  1927. public Node parseFromMain(InputStream inputStream, String filename) {
  1928. if (config.isInlineScript()) {
  1929. return parseInline(inputStream, filename, getCurrentContext().getCurrentScope());
  1930. } else {
  1931. return parseFile(inputStream, filename, getCurrentContext().getCurrentScope());
  1932. }
  1933. }
  1934. /**
  1935. * Run the given script with a "while gets; end" loop wrapped around it.
  1936. * This is primarily used for the -n command-line flag, to allow writing
  1937. * a short script that processes input lines using the specified code.
  1938. *
  1939. * @param scriptNode The root node of the script to execute
  1940. * @param printing Whether $_ should be printed after each loop (as in the
  1941. * -p command-line flag)
  1942. * @param processLineEnds Whether line endings should be processed by
  1943. * setting $\ to $/ and <code>chop!</code>ing every line read
  1944. * @param split Whether to split each line read using <code>String#split</code>
  1945. * @param yarvCompile Whether to compile the target script to YARV (Ruby 1.9)
  1946. * bytecode before executing.
  1947. * @return The result of executing the specified script
  1948. */
  1949. public IRubyObject runWithGetsLoop(Node scriptNode, boolean printing, boolean processLineEnds, boolean split, boolean yarvCompile) {
  1950. ThreadContext context = getCurrentContext();
  1951. Script script = null;
  1952. YARVCompiledRunner runner = null;
  1953. boolean compile = getInstanceConfig().getCompileMode().shouldPrecompileCLI();
  1954. if (compile || !yarvCompile) {
  1955. script = tryCompile(scriptNode);
  1956. if (compile && script == null) {
  1957. // terminate; tryCompile will have printed out an error and we're done
  1958. return getNil();
  1959. }
  1960. } else if (yarvCompile) {
  1961. runner = tryCompileYarv(scriptNode);
  1962. }
  1963. if (processLineEnds) {
  1964. getGlobalVariables().set("$\\", getGlobalVariables().get("$/"));
  1965. }
  1966. while (RubyKernel.gets(context, getTopSelf(), IRubyObject.NULL_ARRAY).isTrue()) {
  1967. loop: while (true) { // Used for the 'redo' command
  1968. try {
  1969. if (processLineEnds) {
  1970. getGlobalVariables().get("$_").callMethod(context, "chop!");
  1971. }
  1972. if (split) {
  1973. getGlobalVariables().set("$F", getGlobalVariables().get("$_").callMethod(context, "split"));
  1974. }
  1975. if (script != null) {
  1976. runScript(script);
  1977. } else if (runner != null) {
  1978. runYarv(runner);
  1979. } else {
  1980. runInterpreter(scriptNode);
  1981. }
  1982. if (printing) RubyKernel.print(context, getKernel(), new IRubyObject[] {getGlobalVariables().get("$_")});
  1983. break loop;
  1984. } catch (JumpException.RedoJump rj) {
  1985. // do nothing, this iteration restarts
  1986. } catch (JumpException.NextJump nj) {
  1987. // recheck condition
  1988. break loop;
  1989. } catch (JumpException.BreakJump bj) {
  1990. // end loop
  1991. return (IRubyObject) bj.getValue();
  1992. }
  1993. }
  1994. }
  1995. return getNil();
  1996. }
  1997. /**
  1998. * Run the specified script without any of the loop-processing wrapper
  1999. * code.
  2000. *
  2001. * @param scriptNode The root node of the script to be executed
  2002. * @param yarvCompile Whether to compile the script to YARV (Ruby 1.9)
  2003. * bytecode before execution
  2004. * @return The result of executing the script
  2005. */
  2006. public IRubyObject runNormally(Node scriptNode, boolean yarvCompile) {
  2007. Script script = null;
  2008. YARVCompiledRunner runner = null;
  2009. boolean compile = getInstanceConfig().getCompileMode().shouldPrecompileCLI();
  2010. boolean forceCompile = getInstanceConfig().getCompileMode().shouldPrecompileAll();
  2011. if (yarvCompile) {
  2012. runner = tryCompileYarv(scriptNode);
  2013. } else if (compile) {
  2014. script = tryCompile(scriptNode);
  2015. if (forceCompile && script == null) {
  2016. System.err.println("Error, could not compile; pass -J-Djruby.jit.logging.verbose=true for more details");
  2017. return getNil();
  2018. }
  2019. }
  2020. if (script != null) {
  2021. if (config.isShowBytecode()) {
  2022. return nilObject;
  2023. } else {
  2024. return runScript(script);
  2025. }
  2026. } else if (runner != null) {
  2027. return runYarv(runner);
  2028. } else {
  2029. if (config.isShowBytecode()) System.err.print("error: bytecode printing only works with JVM bytecode");
  2030. return runInterpreter(scriptNode);
  2031. }
  2032. }
  2033. private Script tryCompile(Node node) {
  2034. return tryCompile(node, new JRubyClassLoader(getJRubyClassLoader()));
  2035. }
  2036. private Script tryCompile(Node node, JRubyClassLoader classLoader) {
  2037. Script script = null;
  2038. try {
  2039. String filename = node.getPosition().getFile();
  2040. String classname = JavaNameMangler.mangledFilenameForStartupClasspath(filename);
  2041. ASTInspector inspector = new ASTInspector();
  2042. inspector.inspect(node);
  2043. StandardASMCompiler asmCompiler = new StandardASMCompiler(classname, filename);
  2044. ASTCompiler compiler = new ASTCompiler();
  2045. if (config.isShowBytecode()) {
  2046. compiler.compileRoot(node, asmCompiler, inspector, false, false);
  2047. asmCompiler.dumpClass(System.out);
  2048. } else {
  2049. compiler.compileRoot(node, asmCompiler, inspector, true, false);
  2050. }
  2051. script = (Script)asmCompiler.loadClass(classLoader).newInstance();
  2052. if (config.isJitLogging()) {
  2053. System.err.println("compiled: " + node.getPosition().getFile());
  2054. }
  2055. } catch (NotCompilableException nce) {
  2056. if (config.isJitLoggingVerbose()) {
  2057. System.err.println("Error -- Not compileable: " + nce.getMessage());
  2058. nce.printStackTrace();
  2059. }
  2060. } catch (ClassNotFoundException e) {
  2061. if (config.isJitLoggingVerbose()) {
  2062. System.err.println("Error -- Not compileable: " + e.getMessage());
  2063. e.printStackTrace();
  2064. }
  2065. } catch (InstantiationException e) {
  2066. if (config.isJitLoggingVerbose()) {
  2067. System.err.println("Error -- Not compileable: " + e.getMessage());
  2068. e.printStackTrace();
  2069. }
  2070. } catch (IllegalAccessException e) {
  2071. if (config.isJitLoggingVerbose()) {
  2072. System.err.println("Error -- Not compileable: " + e.getMessage());
  2073. e.printStackTrace();
  2074. }
  2075. } catch (Throwable t) {
  2076. if (config.isJitLoggingVerbose()) {
  2077. System.err.println("could not compile: " + node.getPosition().getFile() + " because of: \"" + t.getMessage() + "\"");
  2078. t.printStackTrace();
  2079. }
  2080. }
  2081. return script;
  2082. }
  2083. private YARVCompiledRunner tryCompileYarv(Node node) {
  2084. try {
  2085. StandardYARVCompiler compiler = new StandardYARVCompiler(this);
  2086. ASTCompiler.getYARVCompiler().compile(node, compiler);
  2087. org.jruby.lexer.yacc.ISourcePosition p = node.getPosition();
  2088. if(p == null && node instanceof org.jruby.ast.RootNode) {
  2089. p = ((org.jruby.ast.RootNode)node).getBodyNode().getPosition();
  2090. }
  2091. return new YARVCompiledRunner(this,compiler.getInstructionSequence("<main>",p.getFile(),"toplevel"));
  2092. } catch (NotCompilableException nce) {
  2093. System.err.println("Error -- Not compileable: " + nce.getMessage());
  2094. return null;
  2095. } catch (JumpException.ReturnJump rj) {
  2096. return null;
  2097. }
  2098. }
  2099. private IRubyObject runScript(Script script) {
  2100. ThreadContext context = getCurrentContext();
  2101. try {
  2102. return script.load(context, context.getFrameSelf(), IRubyObject.NULL_ARRAY, Block.NULL_BLOCK);
  2103. } catch (JumpException.ReturnJump rj) {
  2104. return (IRubyObject) rj.getValue();
  2105. }
  2106. }
  2107. private IRubyObject runYarv(YARVCompiledRunner runner) {
  2108. try {
  2109. return runner.run();
  2110. } catch (JumpException.ReturnJump rj) {
  2111. return (IRubyObject) rj.getValue();
  2112. }
  2113. }
  2114. private IRubyObject runInterpreter(Node scriptNode) {
  2115. ThreadContext context = getCurrentContext();
  2116. assert scriptNode != null : "scriptNode is not null";
  2117. try {
  2118. return scriptNode.interpret(this, context, getTopSelf(), Block.NULL_BLOCK);
  2119. } catch (JumpException.ReturnJump rj) {
  2120. return (IRubyObject) rj.getValue();
  2121. }
  2122. }
  2123. public BeanManager getBeanManager() {
  2124. return beanManager;
  2125. }
  2126. public JITCompiler getJITCompiler() {
  2127. return jitCompiler;
  2128. }
  2129. /**
  2130. * @deprecated use #newInstance()
  2131. */
  2132. public static Ruby getDefaultInstance() {
  2133. return newInstance();
  2134. }
  2135. @Deprecated
  2136. public static Ruby getCurrentInstance() {
  2137. return null;
  2138. }
  2139. @Deprecated
  2140. public static void setCurrentInstance(Ruby runtime) {
  2141. }
  2142. public int allocSymbolId() {
  2143. return symbolLastId.incrementAndGet();
  2144. }
  2145. public int allocModuleId() {
  2146. return moduleLastId.incrementAndGet();
  2147. }
  2148. /**
  2149. * Retrieve the module with the given name from the Object namespace.
  2150. *
  2151. * @param name The name of the module
  2152. * @return The module or null if not found
  2153. */
  2154. public RubyModule getModule(String name) {
  2155. return (RubyModule) objectClass.getConstantAt(name);
  2156. }
  2157. /**
  2158. * Retrieve the module with the given name from the Object namespace. The
  2159. * module name must be an interned string, but this method will be faster
  2160. * than the non-interned version.
  2161. *
  2162. * @param internedName The name of the module; <em>must</em> be an interned String
  2163. * @return The module or null if not found
  2164. */
  2165. public RubyModule fastGetModule(String internedName) {
  2166. return (RubyModule) objectClass.fastGetConstantAt(internedName);
  2167. }
  2168. /**
  2169. * Retrieve the class with the given name from the Object namespace.
  2170. *
  2171. * @param name The name of the class
  2172. * @return The class
  2173. */
  2174. public RubyClass getClass(String name) {
  2175. return objectClass.getClass(name);
  2176. }
  2177. /**
  2178. * Retrieve the class with the given name from the Object namespace. The
  2179. * module name must be an interned string, but this method will be faster
  2180. * than the non-interned version.
  2181. *
  2182. * @param internedName the name of the class; <em>must</em> be an interned String!
  2183. * @return
  2184. */
  2185. public RubyClass fastGetClass(String internedName) {
  2186. return objectClass.fastGetClass(internedName);
  2187. }
  2188. /**
  2189. * Define a new class under the Object namespace. Roughly equivalent to
  2190. * rb_define_class in MRI.
  2191. *
  2192. * @param name The name for the new class
  2193. * @param superClass The super class for the new class
  2194. * @param allocator An ObjectAllocator instance that can construct
  2195. * instances of the new class.
  2196. * @return The new class
  2197. */
  2198. public RubyClass defineClass(String name, RubyClass superClass, ObjectAllocator allocator) {
  2199. return defineClassUnder(name, superClass, allocator, objectClass);
  2200. }
  2201. /**
  2202. * A variation of defineClass that allows passing in an array of subplementary
  2203. * call sites for improving dynamic invocation performance.
  2204. *
  2205. * @param name The name for the new class
  2206. * @param superClass The super class for the new class
  2207. * @param allocator An ObjectAllocator instance that can construct
  2208. * instances of the new class.
  2209. * @return The new class
  2210. */
  2211. public RubyClass defineClass(String name, RubyClass superClass, ObjectAllocator allocator, CallSite[] callSites) {
  2212. return defineClassUnder(name, superClass, allocator, objectClass, callSites);
  2213. }
  2214. /**
  2215. * Define a new class with the given name under the given module or class
  2216. * namespace. Roughly equivalent to rb_define_class_under in MRI.
  2217. *
  2218. * If the name specified is already bound, its value will be returned if:
  2219. * * It is a class
  2220. * * No new superclass is being defined
  2221. *
  2222. * @param name The name for the new class
  2223. * @param superClass The super class for the new class
  2224. * @param allocator An ObjectAllocator instance that can construct
  2225. * instances of the new class.
  2226. * @param parent The namespace under which to define the new class
  2227. * @return The new class
  2228. */
  2229. public RubyClass defineClassUnder(String name, RubyClass superClass, ObjectAllocator allocator, RubyModule parent) {
  2230. return defineClassUnder(name, superClass, allocator, parent, null);
  2231. }
  2232. /**
  2233. * A variation of defineClassUnder that allows passing in an array of
  2234. * supplementary call sites to improve dynamic invocation.
  2235. *
  2236. * @param name The name for the new class
  2237. * @param superClass The super class for the new class
  2238. * @param allocator An ObjectAllocator instance that can construct
  2239. * instances of the new class.
  2240. * @param parent The namespace under which to define the new class
  2241. * @param callSites The array of call sites to add
  2242. * @return The new class
  2243. */
  2244. public RubyClass defineClassUnder(String name, RubyClass superClass, ObjectAllocator allocator, RubyModule parent, CallSite[] callSites) {
  2245. IRubyObject classObj = parent.getConstantAt(name);
  2246. if (classObj != null) {
  2247. if (!(classObj instanceof RubyClass)) throw newTypeError(name + " is not a class");
  2248. RubyClass klazz = (RubyClass)classObj;
  2249. if (klazz.getSuperClass().getRealClass() != superClass) {
  2250. throw newNameError(name + " is already defined", name);
  2251. }
  2252. // If we define a class in Ruby, but later want to allow it to be defined in Java,
  2253. // the allocator needs to be updated
  2254. if (klazz.getAllocator() != allocator) {
  2255. klazz.setAllocator(allocator);
  2256. }
  2257. return klazz;
  2258. }
  2259. boolean parentIsObject = parent == objectClass;
  2260. if (superClass == null) {
  2261. String className = parentIsObject ? name : parent.getName() + "::" + name;
  2262. warnings.warn(ID.NO_SUPER_CLASS, "no super class for `" + className + "', Object assumed", className);
  2263. superClass = objectClass;
  2264. }
  2265. return RubyClass.newClass(this, superClass, name, allocator, parent, !parentIsObject, callSites);
  2266. }
  2267. /**
  2268. * Define a new module under the Object namespace. Roughly equivalent to
  2269. * rb_define_module in MRI.
  2270. *
  2271. * @param name The name of the new module
  2272. * @returns The new module
  2273. */
  2274. public RubyModule defineModule(String name) {
  2275. return defineModuleUnder(name, objectClass);
  2276. }
  2277. /**
  2278. * Define a new module with the given name under the given module or
  2279. * class namespace. Roughly equivalent to rb_define_module_under in MRI.
  2280. *
  2281. * @param name The name of the new module
  2282. * @param parent The class or module namespace under which to define the
  2283. * module
  2284. * @returns The new module
  2285. */
  2286. public RubyModule defineModuleUnder(String name, RubyModule parent) {
  2287. IRubyObject moduleObj = parent.getConstantAt(name);
  2288. boolean parentIsObject = parent == objectClass;
  2289. if (moduleObj != null ) {
  2290. if (moduleObj.isModule()) return (RubyModule)moduleObj;
  2291. if (parentIsObject) {
  2292. throw newTypeError(moduleObj.getMetaClass().getName() + " is not a module");
  2293. } else {
  2294. throw newTypeError(parent.getName() + "::" + moduleObj.getMetaClass().getName() + " is not a module");
  2295. }
  2296. }
  2297. return RubyModule.newModule(this, name, parent, !parentIsObject);
  2298. }
  2299. /**
  2300. * From Object, retrieve the named module. If it doesn't exist a
  2301. * new module is created.
  2302. *
  2303. * @param name The name of the module
  2304. * @returns The existing or new module
  2305. */
  2306. public RubyModule getOrCreateModule(String name) {
  2307. IRubyObject module = objectClass.getConstantAt(name);
  2308. if (module == null) {
  2309. module = defineModule(name);
  2310. } else if (getSafeLevel() >= 4) {
  2311. throw newSecurityError("Extending module prohibited.");
  2312. } else if (!module.isModule()) {
  2313. throw newTypeError(name + " is not a Module");
  2314. }
  2315. return (RubyModule) module;
  2316. }
  2317. /**
  2318. * Retrieve the current safe level.
  2319. *
  2320. * @see org.jruby.Ruby#setSaveLevel
  2321. */
  2322. public int getSafeLevel() {
  2323. return this.safeLevel;
  2324. }
  2325. /**
  2326. * Set the current safe level:
  2327. *
  2328. * 0 - strings from streams/environment/ARGV are tainted (default)
  2329. * 1 - no dangerous operation by tainted value
  2330. * 2 - process/file operations prohibited
  2331. * 3 - all generated objects are tainted
  2332. * 4 - no global (non-tainted) variable modification/no direct output
  2333. *
  2334. * The safe level is set using $SAFE in Ruby code. It is not particularly
  2335. * well supported in JRuby.
  2336. */
  2337. public void setSafeLevel(int safeLevel) {
  2338. this.safeLevel = safeLevel;
  2339. }
  2340. public KCode getKCode() {
  2341. return kcode;
  2342. }
  2343. public void setKCode(KCode kcode) {
  2344. this.kcode = kcode;
  2345. }
  2346. public void secure(int level) {
  2347. if (level <= safeLevel) {
  2348. throw newSecurityError("Insecure operation '" + getCurrentContext().getFrameName() + "' at level " + safeLevel);
  2349. }
  2350. }
  2351. // FIXME moved this here to get what's obviously a utility method out of IRubyObject.
  2352. // perhaps security methods should find their own centralized home at some point.
  2353. public void checkSafeString(IRubyObject object) {
  2354. if (getSafeLevel() > 0 && object.isTaint()) {
  2355. ThreadContext tc = getCurrentContext();
  2356. if (tc.getFrameName() != null) {
  2357. throw newSecurityError("Insecure operation - " + tc.getFrameName());
  2358. }
  2359. throw newSecurityError("Insecure operation: -r");
  2360. }
  2361. secure(4);
  2362. if (!(object instanceof RubyString)) {
  2363. throw newTypeError(
  2364. "wrong argument type " + object.getMetaClass().getName() + " (expected String)");
  2365. }
  2366. }
  2367. /** rb_define_global_const
  2368. *
  2369. */
  2370. public void defineGlobalConstant(String name, IRubyObject value) {
  2371. objectClass.defineConstant(name, value);
  2372. }
  2373. public boolean isClassDefined(String name) {
  2374. return getModule(name) != null;
  2375. }
  2376. /**
  2377. * A ThreadFactory for when we're using pooled threads; we want to create
  2378. * the threads with daemon = true so they don't keep us from shutting down.
  2379. */
  2380. public static class DaemonThreadFactory implements ThreadFactory {
  2381. public Thread newThread(Runnable runnable) {
  2382. Thread thread = new Thread(runnable);
  2383. thread.setDaemon(true);
  2384. return thread;
  2385. }
  2386. }
  2387. /**
  2388. * This method is called immediately after constructing the Ruby instance.
  2389. * The main thread is prepared for execution, all core classes and libraries
  2390. * are initialized, and any libraries required on the command line are
  2391. * loaded.
  2392. */
  2393. private void init() {
  2394. // Get the main threadcontext (gets constructed for us)
  2395. ThreadContext tc = getCurrentContext();
  2396. safeLevel = config.getSafeLevel();
  2397. // Construct key services
  2398. loadService = config.createLoadService(this);
  2399. posix = POSIXFactory.getPOSIX(new JRubyPOSIXHandler(this), RubyInstanceConfig.nativeEnabled);
  2400. javaSupport = new JavaSupport(this);
  2401. if (RubyInstanceConfig.POOLING_ENABLED) {
  2402. Executors.newCachedThreadPool();
  2403. executor = new ThreadPoolExecutor(
  2404. RubyInstanceConfig.POOL_MIN,
  2405. RubyInstanceConfig.POOL_MAX,
  2406. RubyInstanceConfig.POOL_TTL,
  2407. TimeUnit.SECONDS,
  2408. new SynchronousQueue<Runnable>(),
  2409. new DaemonThreadFactory());
  2410. }
  2411. // initialize the root of the class hierarchy completely
  2412. initRoot(tc);
  2413. // Construct the top-level execution frame and scope for the main thread
  2414. tc.prepareTopLevel(objectClass, topSelf);
  2415. // Initialize all the core classes
  2416. bootstrap();
  2417. // Create global constants and variables
  2418. RubyGlobal.createGlobals(tc, this);
  2419. // Prepare LoadService and load path
  2420. getLoadService().init(config.loadPaths());
  2421. // initialize builtin libraries
  2422. initBuiltins();
  2423. // Require in all libraries specified on command line
  2424. for (String scriptName : config.requiredLibraries()) {
  2425. RubyKernel.require(getTopSelf(), newString(scriptName), Block.NULL_BLOCK);
  2426. }
  2427. }
  2428. private void bootstrap() {
  2429. initCore();
  2430. initExceptions();
  2431. }
  2432. private void initRoot(ThreadContext context) {
  2433. // Bootstrap the top of the hierarchy
  2434. objectClass = RubyClass.createBootstrapClass(this, "Object", null, RubyObject.OBJECT_ALLOCATOR);
  2435. moduleClass = RubyClass.createBootstrapClass(this, "Module", objectClass, RubyModule.MODULE_ALLOCATOR);
  2436. classClass = RubyClass.createBootstrapClass(this, "Class", moduleClass, RubyClass.CLASS_ALLOCATOR);
  2437. objectClass.setMetaClass(classClass);
  2438. moduleClass.setMetaClass(classClass);
  2439. classClass.setMetaClass(classClass);
  2440. RubyClass metaClass;
  2441. metaClass = objectClass.makeMetaClass(classClass);
  2442. metaClass = moduleClass.makeMetaClass(metaClass);
  2443. metaClass = classClass.makeMetaClass(metaClass);
  2444. RubyObject.createObjectClass(this, objectClass);
  2445. RubyModule.createModuleClass(this, moduleClass);
  2446. RubyClass.createClassClass(this, classClass);
  2447. // set constants now that they're initialized
  2448. objectClass.setConstant("Object", objectClass);
  2449. objectClass.setConstant("Class", classClass);
  2450. objectClass.setConstant("Module", moduleClass);
  2451. // Initialize Kernel and include into Object
  2452. RubyKernel.createKernelModule(this);
  2453. objectClass.includeModule(kernelModule);
  2454. // Initialize the "dummy" class used as a marker
  2455. dummyClass = new RubyClass(this);
  2456. dummyClass.freeze(context);
  2457. // Object is ready, create top self
  2458. topSelf = TopSelfFactory.createTopSelf(this);
  2459. }
  2460. private void initCore() {
  2461. // Pre-create all the core classes potentially referenced during startup
  2462. RubyNil.createNilClass(this);
  2463. RubyBoolean.createFalseClass(this);
  2464. RubyBoolean.createTrueClass(this);
  2465. nilObject = new RubyNil(this);
  2466. falseObject = new RubyBoolean(this, false);
  2467. trueObject = new RubyBoolean(this, true);
  2468. RubyComparable.createComparable(this);
  2469. RubyEnumerable.createEnumerableModule(this);
  2470. RubyString.createStringClass(this);
  2471. RubySymbol.createSymbolClass(this);
  2472. if (profile.allowClass("ThreadGroup")) {
  2473. RubyThreadGroup.createThreadGroupClass(this);
  2474. }
  2475. if (profile.allowClass("Thread")) {
  2476. RubyThread.createThreadClass(this);
  2477. }
  2478. if (profile.allowClass("Exception")) {
  2479. RubyException.createExceptionClass(this);
  2480. }
  2481. if (profile.allowModule("Precision")) {
  2482. RubyPrecision.createPrecisionModule(this);
  2483. }
  2484. if (profile.allowClass("Numeric")) {
  2485. RubyNumeric.createNumericClass(this);
  2486. }
  2487. if (profile.allowClass("Integer")) {
  2488. RubyInteger.createIntegerClass(this);
  2489. }
  2490. if (profile.allowClass("Fixnum")) {
  2491. RubyFixnum.createFixnumClass(this);
  2492. }
  2493. if (config.getCompatVersion() == CompatVersion.RUBY1_9) {
  2494. if (profile.allowClass("Complex")) {
  2495. RubyComplex.createComplexClass(this);
  2496. }
  2497. if (profile.allowClass("Rational")) {
  2498. RubyRational.createRationalClass(this);
  2499. }
  2500. }
  2501. if (profile.allowClass("Hash")) {
  2502. RubyHash.createHashClass(this);
  2503. }
  2504. if (profile.allowClass("Array")) {
  2505. RubyArray.createArrayClass(this);
  2506. }
  2507. if (profile.allowClass("Float")) {
  2508. RubyFloat.createFloatClass(this);
  2509. }
  2510. if (profile.allowClass("Bignum")) {
  2511. RubyBignum.createBignumClass(this);
  2512. }
  2513. ioClass = RubyIO.createIOClass(this);
  2514. if (profile.allowClass("Struct")) {
  2515. RubyStruct.createStructClass(this);
  2516. }
  2517. if (profile.allowClass("Tms")) {
  2518. tmsStruct = RubyStruct.newInstance(structClass, new IRubyObject[]{newString("Tms"), newSymbol("utime"), newSymbol("stime"), newSymbol("cutime"), newSymbol("cstime")}, Block.NULL_BLOCK);
  2519. }
  2520. if (profile.allowClass("Binding")) {
  2521. RubyBinding.createBindingClass(this);
  2522. }
  2523. // Math depends on all numeric types
  2524. if (profile.allowModule("Math")) {
  2525. RubyMath.createMathModule(this);
  2526. }
  2527. if (profile.allowClass("Regexp")) {
  2528. RubyRegexp.createRegexpClass(this);
  2529. }
  2530. if (profile.allowClass("Range")) {
  2531. RubyRange.createRangeClass(this);
  2532. }
  2533. if (profile.allowModule("ObjectSpace")) {
  2534. RubyObjectSpace.createObjectSpaceModule(this);
  2535. }
  2536. if (profile.allowModule("GC")) {
  2537. RubyGC.createGCModule(this);
  2538. }
  2539. if (profile.allowClass("Proc")) {
  2540. RubyProc.createProcClass(this);
  2541. }
  2542. if (profile.allowClass("Method")) {
  2543. RubyMethod.createMethodClass(this);
  2544. }
  2545. if (profile.allowClass("MatchData")) {
  2546. RubyMatchData.createMatchDataClass(this);
  2547. }
  2548. if (profile.allowModule("Marshal")) {
  2549. RubyMarshal.createMarshalModule(this);
  2550. }
  2551. if (profile.allowClass("Dir")) {
  2552. RubyDir.createDirClass(this);
  2553. }
  2554. if (profile.allowModule("FileTest")) {
  2555. RubyFileTest.createFileTestModule(this);
  2556. }
  2557. // depends on IO, FileTest
  2558. if (profile.allowClass("File")) {
  2559. RubyFile.createFileClass(this);
  2560. }
  2561. if (profile.allowClass("File::Stat")) {
  2562. RubyFileStat.createFileStatClass(this);
  2563. }
  2564. if (profile.allowModule("Process")) {
  2565. RubyProcess.createProcessModule(this);
  2566. }
  2567. if (profile.allowClass("Time")) {
  2568. RubyTime.createTimeClass(this);
  2569. }
  2570. if (profile.allowClass("UnboundMethod")) {
  2571. RubyUnboundMethod.defineUnboundMethodClass(this);
  2572. }
  2573. if (profile.allowClass("Data")) {
  2574. defineClass("Data", objectClass, objectClass.getAllocator());
  2575. }
  2576. if (!isSecurityRestricted()) {
  2577. // Signal uses sun.misc.* classes, this is not allowed
  2578. // in the security-sensitive environments
  2579. if (profile.allowModule("Signal")) {
  2580. RubySignal.createSignal(this);
  2581. }
  2582. }
  2583. if (profile.allowClass("Continuation")) {
  2584. RubyContinuation.createContinuation(this);
  2585. }
  2586. }
  2587. private void initExceptions() {
  2588. standardError = defineClassIfAllowed("StandardError", exceptionClass);
  2589. runtimeError = defineClassIfAllowed("RuntimeError", standardError);
  2590. ioError = defineClassIfAllowed("IOError", standardError);
  2591. scriptError = defineClassIfAllowed("ScriptError", exceptionClass);
  2592. rangeError = defineClassIfAllowed("RangeError", standardError);
  2593. signalException = defineClassIfAllowed("SignalException", exceptionClass);
  2594. if (profile.allowClass("NameError")) {
  2595. nameError = RubyNameError.createNameErrorClass(this, standardError);
  2596. nameErrorMessage = RubyNameError.createNameErrorMessageClass(this, nameError);
  2597. }
  2598. if (profile.allowClass("NoMethodError")) {
  2599. noMethodError = RubyNoMethodError.createNoMethodErrorClass(this, nameError);
  2600. }
  2601. if (profile.allowClass("SystemExit")) {
  2602. systemExit = RubySystemExit.createSystemExitClass(this, exceptionClass);
  2603. }
  2604. if (profile.allowClass("LocalJumpError")) {
  2605. localJumpError = RubyLocalJumpError.createLocalJumpErrorClass(this, standardError);
  2606. }
  2607. if (profile.allowClass("NativeException")) {
  2608. nativeException = NativeException.createClass(this, runtimeError);
  2609. }
  2610. if (profile.allowClass("SystemCallError")) {
  2611. systemCallError = RubySystemCallError.createSystemCallErrorClass(this, standardError);
  2612. }
  2613. fatal = defineClassIfAllowed("Fatal", exceptionClass);
  2614. interrupt = defineClassIfAllowed("Interrupt", signalException);
  2615. typeError = defineClassIfAllowed("TypeError", standardError);
  2616. argumentError = defineClassIfAllowed("ArgumentError", standardError);
  2617. indexError = defineClassIfAllowed("IndexError", standardError);
  2618. syntaxError = defineClassIfAllowed("SyntaxError", scriptError);
  2619. loadError = defineClassIfAllowed("LoadError", scriptError);
  2620. notImplementedError = defineClassIfAllowed("NotImplementedError", scriptError);
  2621. securityError = defineClassIfAllowed("SecurityError", standardError);
  2622. noMemoryError = defineClassIfAllowed("NoMemoryError", exceptionClass);
  2623. regexpError = defineClassIfAllowed("RegexpError", standardError);
  2624. eofError = defineClassIfAllowed("EOFError", ioError);
  2625. threadError = defineClassIfAllowed("ThreadError", standardError);
  2626. concurrencyError = defineClassIfAllowed("ConcurrencyError", threadError);
  2627. systemStackError = defineClassIfAllowed("SystemStackError", standardError);
  2628. zeroDivisionError = defineClassIfAllowed("ZeroDivisionError", standardError);
  2629. floatDomainError = defineClassIfAllowed("FloatDomainError", rangeError);
  2630. initErrno();
  2631. }
  2632. private RubyClass defineClassIfAllowed(String name, RubyClass superClass) {
  2633. // TODO: should probably apply the null object pattern for a
  2634. // non-allowed class, rather than null
  2635. if (superClass != null && profile.allowClass(name)) {
  2636. return defineClass(name, superClass, superClass.getAllocator());
  2637. }
  2638. return null;
  2639. }
  2640. private Map<Integer, RubyClass> errnos = new HashMap<Integer, RubyClass>();
  2641. public RubyClass getErrno(int n) {
  2642. return errnos.get(n);
  2643. }
  2644. /**
  2645. * Create module Errno's Variables. We have this method since Errno does not have it's
  2646. * own java class.
  2647. */
  2648. private void initErrno() {
  2649. if (profile.allowModule("Errno")) {
  2650. errnoModule = defineModule("Errno");
  2651. Field[] fields = IErrno.class.getFields();
  2652. for (int i = 0; i < fields.length; i++) {
  2653. try {
  2654. createSysErr(fields[i].getInt(IErrno.class), fields[i].getName());
  2655. } catch (IllegalAccessException e) {
  2656. throw new RuntimeException("Someone defined a non-public constant in IErrno.java", e);
  2657. }
  2658. }
  2659. }
  2660. }
  2661. /**
  2662. * Creates a system error.
  2663. * @param i the error code (will probably use a java exception instead)
  2664. * @param name of the error to define.
  2665. **/
  2666. private void createSysErr(int i, String name) {
  2667. if(profile.allowClass(name)) {
  2668. RubyClass errno = getErrno().defineClassUnder(name, systemCallError, systemCallError.getAllocator());
  2669. errnos.put(i, errno);
  2670. errno.defineConstant("Errno", newFixnum(i));
  2671. }
  2672. }
  2673. private void initBuiltins() {
  2674. addLazyBuiltin("java.rb", "java", "org.jruby.javasupport.Java");
  2675. addLazyBuiltin("jruby.rb", "jruby", "org.jruby.libraries.JRubyLibrary");
  2676. addLazyBuiltin("minijava.rb", "minijava", "org.jruby.java.MiniJava");
  2677. addLazyBuiltin("jruby/ext.rb", "jruby/ext", "org.jruby.RubyJRuby$ExtLibrary");
  2678. addLazyBuiltin("jruby/type.rb", "jruby/type", "org.jruby.RubyJRuby$TypeLibrary");
  2679. addLazyBuiltin("iconv.so", "iconv", "org.jruby.libraries.IConvLibrary");
  2680. addLazyBuiltin("nkf.so", "nkf", "org.jruby.libraries.NKFLibrary");
  2681. addLazyBuiltin("stringio.so", "stringio", "org.jruby.libraries.StringIOLibrary");
  2682. addLazyBuiltin("strscan.so", "strscan", "org.jruby.libraries.StringScannerLibrary");
  2683. addLazyBuiltin("zlib.so", "zlib", "org.jruby.libraries.ZlibLibrary");
  2684. addLazyBuiltin("yaml_internal.rb", "yaml_internal", "org.jruby.libraries.YamlLibrary");
  2685. addLazyBuiltin("enumerator.so", "enumerator", "org.jruby.libraries.EnumeratorLibrary");
  2686. addLazyBuiltin("generator_internal.rb", "generator_internal", "org.jruby.ext.Generator$Service");
  2687. addLazyBuiltin("readline.so", "readline", "org.jruby.ext.Readline$Service");
  2688. addLazyBuiltin("thread.so", "thread", "org.jruby.libraries.ThreadLibrary");
  2689. addLazyBuiltin("digest.so", "digest", "org.jruby.libraries.DigestLibrary");
  2690. addLazyBuiltin("digest.rb", "digest", "org.jruby.libraries.DigestLibrary");
  2691. addLazyBuiltin("digest/md5.so", "digest/md5", "org.jruby.libraries.DigestLibrary$MD5");
  2692. addLazyBuiltin("digest/rmd160.so", "digest/rmd160", "org.jruby.libraries.DigestLibrary$RMD160");
  2693. addLazyBuiltin("digest/sha1.so", "digest/sha1", "org.jruby.libraries.DigestLibrary$SHA1");
  2694. addLazyBuiltin("digest/sha2.so", "digest/sha2", "org.jruby.libraries.DigestLibrary$SHA2");
  2695. addLazyBuiltin("bigdecimal.so", "bigdecimal", "org.jruby.libraries.BigDecimalLibrary");
  2696. addLazyBuiltin("io/wait.so", "io/wait", "org.jruby.libraries.IOWaitLibrary");
  2697. addLazyBuiltin("etc.so", "etc", "org.jruby.libraries.EtcLibrary");
  2698. addLazyBuiltin("weakref.rb", "weakref", "org.jruby.ext.WeakRef$WeakRefLibrary");
  2699. addLazyBuiltin("socket.so", "socket", "org.jruby.ext.socket.RubySocket$Service");
  2700. addLazyBuiltin("rbconfig.rb", "rbconfig", "org.jruby.libraries.RbConfigLibrary");
  2701. addLazyBuiltin("jruby/serialization.rb", "serialization", "org.jruby.libraries.JRubySerializationLibrary");
  2702. addLazyBuiltin("ffi.so", "ffi", "org.jruby.ext.ffi.Factory$Service");
  2703. if(RubyInstanceConfig.NATIVE_NET_PROTOCOL) {
  2704. addLazyBuiltin("net/protocol.rb", "net/protocol", "org.jruby.libraries.NetProtocolBufferedIOLibrary");
  2705. }
  2706. if (config.getCompatVersion() == CompatVersion.RUBY1_9) {
  2707. addLazyBuiltin("fiber.so", "fiber", "org.jruby.libraries.FiberLibrary");
  2708. }
  2709. addBuiltinIfAllowed("openssl.so", new Library() {
  2710. public void load(Ruby runtime, boolean wrap) throws IOException {
  2711. runtime.getLoadService().require("jruby/openssl/stub");
  2712. }
  2713. });
  2714. String[] builtins = {"fcntl", "yaml", "yaml/syck", "jsignal" };
  2715. for (String library : builtins) {
  2716. addBuiltinIfAllowed(library + ".rb", new BuiltinScript(library));
  2717. }
  2718. getLoadService().require("builtin/core_ext/symbol");
  2719. RubyKernel.autoload(topSelf, newSymbol("Java"), newString("java"));
  2720. getLoadService().require("enumerator");
  2721. }
  2722. private void addLazyBuiltin(String name, String shortName, String className) {
  2723. addBuiltinIfAllowed(name, new LateLoadingLibrary(shortName, className, getJRubyClassLoader()));
  2724. }
  2725. private void addBuiltinIfAllowed(String name, Library lib) {
  2726. if(profile.allowBuiltin(name)) {
  2727. loadService.addBuiltinLibrary(name,lib);
  2728. }
  2729. }
  2730. Object getRespondToMethod() {
  2731. return respondToMethod;
  2732. }
  2733. void setRespondToMethod(Object rtm) {
  2734. this.respondToMethod = rtm;
  2735. }
  2736. public Object getObjectToYamlMethod() {
  2737. return objectToYamlMethod;
  2738. }
  2739. void setObjectToYamlMethod(Object otym) {
  2740. this.objectToYamlMethod = otym;
  2741. }
  2742. /**
  2743. * Retrieve mappings of cached methods to where they have been cached. When a cached
  2744. * method needs to be invalidated this map can be used to remove all places it has been
  2745. * cached.
  2746. *
  2747. * @return the mappings of where cached methods have been stored
  2748. */
  2749. public CacheMap getCacheMap() {
  2750. return cacheMap;
  2751. }
  2752. /** Getter for property rubyTopSelf.
  2753. * @return Value of property rubyTopSelf.
  2754. */
  2755. public IRubyObject getTopSelf() {
  2756. return topSelf;
  2757. }
  2758. public void setCurrentDirectory(String dir) {
  2759. currentDirectory = dir;
  2760. }
  2761. public String getCurrentDirectory() {
  2762. return currentDirectory;
  2763. }
  2764. public RubyModule getEtc() {
  2765. return etcModule;
  2766. }
  2767. public void setEtc(RubyModule etcModule) {
  2768. this.etcModule = etcModule;
  2769. }
  2770. public RubyClass getObject() {
  2771. return objectClass;
  2772. }
  2773. public RubyClass getModule() {
  2774. return moduleClass;
  2775. }
  2776. public RubyClass getClassClass() {
  2777. return classClass;
  2778. }
  2779. public RubyModule getKernel() {
  2780. return kernelModule;
  2781. }
  2782. void setKernel(RubyModule kernelModule) {
  2783. this.kernelModule = kernelModule;
  2784. }
  2785. public RubyClass getDummy() {
  2786. return dummyClass;
  2787. }
  2788. public RubyModule getComparable() {
  2789. return comparableModule;
  2790. }
  2791. void setComparable(RubyModule comparableModule) {
  2792. this.comparableModule = comparableModule;
  2793. }
  2794. public RubyClass getNumeric() {
  2795. return numericClass;
  2796. }
  2797. void setNumeric(RubyClass numericClass) {
  2798. this.numericClass = numericClass;
  2799. }
  2800. public RubyClass getFloat() {
  2801. return floatClass;
  2802. }
  2803. void setFloat(RubyClass floatClass) {
  2804. this.floatClass = floatClass;
  2805. }
  2806. public RubyClass getInteger() {
  2807. return integerClass;
  2808. }
  2809. void setInteger(RubyClass integerClass) {
  2810. this.integerClass = integerClass;
  2811. }
  2812. public RubyClass getFixnum() {
  2813. return fixnumClass;
  2814. }
  2815. void setFixnum(RubyClass fixnumClass) {
  2816. this.fixnumClass = fixnumClass;
  2817. }
  2818. public RubyClass getComplex() {
  2819. return complexClass;
  2820. }
  2821. void setComplex(RubyClass complexClass) {
  2822. this.complexClass = complexClass;
  2823. }
  2824. public RubyClass getRational() {
  2825. return rationalClass;
  2826. }
  2827. void setRational(RubyClass rationalClass) {
  2828. this.rationalClass = rationalClass;
  2829. }
  2830. public RubyModule getEnumerable() {
  2831. return enumerableModule;
  2832. }
  2833. void setEnumerable(RubyModule enumerableModule) {
  2834. this.enumerableModule = enumerableModule;
  2835. }
  2836. public RubyModule getEnumerator() {
  2837. return enumeratorClass;
  2838. }
  2839. void setEnumerator(RubyClass enumeratorClass) {
  2840. this.enumeratorClass = enumeratorClass;
  2841. }
  2842. public RubyClass getString() {
  2843. return stringClass;
  2844. }
  2845. void setString(RubyClass stringClass) {
  2846. this.stringClass = stringClass;
  2847. }
  2848. public RubyClass getSymbol() {
  2849. return symbolClass;
  2850. }
  2851. void setSymbol(RubyClass symbolClass) {
  2852. this.symbolClass = symbolClass;
  2853. }
  2854. public RubyClass getArray() {
  2855. return arrayClass;
  2856. }
  2857. void setArray(RubyClass arrayClass) {
  2858. this.arrayClass = arrayClass;
  2859. }
  2860. public RubyClass getHash() {
  2861. return hashClass;
  2862. }
  2863. void setHash(RubyClass hashClass) {
  2864. this.hashClass = hashClass;
  2865. }
  2866. public RubyClass getRange() {
  2867. return rangeClass;
  2868. }
  2869. void setRange(RubyClass rangeClass) {
  2870. this.rangeClass = rangeClass;
  2871. }
  2872. /** Returns the "true" instance from the instance pool.
  2873. * @return The "true" instance.
  2874. */
  2875. public RubyBoolean getTrue() {
  2876. return trueObject;
  2877. }
  2878. /** Returns the "false" instance from the instance pool.
  2879. * @return The "false" instance.
  2880. */
  2881. public RubyBoolean getFalse() {
  2882. return falseObject;
  2883. }
  2884. /** Returns the "nil" singleton instance.
  2885. * @return "nil"
  2886. */
  2887. public IRubyObject getNil() {
  2888. return nilObject;
  2889. }
  2890. public RubyClass getNilClass() {
  2891. return nilClass;
  2892. }
  2893. void setNilClass(RubyClass nilClass) {
  2894. this.nilClass = nilClass;
  2895. }
  2896. public RubyClass getTrueClass() {
  2897. return trueClass;
  2898. }
  2899. void setTrueClass(RubyClass trueClass) {
  2900. this.trueClass = trueClass;
  2901. }
  2902. public RubyClass getFalseClass() {
  2903. return falseClass;
  2904. }
  2905. void setFalseClass(RubyClass falseClass) {
  2906. this.falseClass = falseClass;
  2907. }
  2908. public RubyClass getProc() {
  2909. return procClass;
  2910. }
  2911. void setProc(RubyClass procClass) {
  2912. this.procClass = procClass;
  2913. }
  2914. public RubyClass getBinding() {
  2915. return bindingClass;
  2916. }
  2917. void setBinding(RubyClass bindingClass) {
  2918. this.bindingClass = bindingClass;
  2919. }
  2920. public RubyClass getMethod() {
  2921. return methodClass;
  2922. }
  2923. void setMethod(RubyClass methodClass) {
  2924. this.methodClass = methodClass;
  2925. }
  2926. public RubyClass getUnboundMethod() {
  2927. return unboundMethodClass;
  2928. }
  2929. void setUnboundMethod(RubyClass unboundMethodClass) {
  2930. this.unboundMethodClass = unboundMethodClass;
  2931. }
  2932. public RubyClass getMatchData() {
  2933. return matchDataClass;
  2934. }
  2935. void setMatchData(RubyClass matchDataClass) {
  2936. this.matchDataClass = matchDataClass;
  2937. }
  2938. public RubyClass getRegexp() {
  2939. return regexpClass;
  2940. }
  2941. void setRegexp(RubyClass regexpClass) {
  2942. this.regexpClass = regexpClass;
  2943. }
  2944. public RubyClass getTime() {
  2945. return timeClass;
  2946. }
  2947. void setTime(RubyClass timeClass) {
  2948. this.timeClass = timeClass;
  2949. }
  2950. public RubyModule getMath() {
  2951. return mathModule;
  2952. }
  2953. void setMath(RubyModule mathModule) {
  2954. this.mathModule = mathModule;
  2955. }
  2956. public RubyModule getMarshal() {
  2957. return marshalModule;
  2958. }
  2959. void setMarshal(RubyModule marshalModule) {
  2960. this.marshalModule = marshalModule;
  2961. }
  2962. public RubyClass getBignum() {
  2963. return bignumClass;
  2964. }
  2965. void setBignum(RubyClass bignumClass) {
  2966. this.bignumClass = bignumClass;
  2967. }
  2968. public RubyClass getDir() {
  2969. return dirClass;
  2970. }
  2971. void setDir(RubyClass dirClass) {
  2972. this.dirClass = dirClass;
  2973. }
  2974. public RubyClass getFile() {
  2975. return fileClass;
  2976. }
  2977. void setFile(RubyClass fileClass) {
  2978. this.fileClass = fileClass;
  2979. }
  2980. public RubyClass getFileStat() {
  2981. return fileStatClass;
  2982. }
  2983. void setFileStat(RubyClass fileStatClass) {
  2984. this.fileStatClass = fileStatClass;
  2985. }
  2986. public RubyModule getFileTest() {
  2987. return fileTestModule;
  2988. }
  2989. void setFileTest(RubyModule fileTestModule) {
  2990. this.fileTestModule = fileTestModule;
  2991. }
  2992. public RubyClass getIO() {
  2993. return ioClass;
  2994. }
  2995. void setIO(RubyClass ioClass) {
  2996. this.ioClass = ioClass;
  2997. }
  2998. public RubyClass getThread() {
  2999. return threadClass;
  3000. }
  3001. void setThread(RubyClass threadClass) {
  3002. this.threadClass = threadClass;
  3003. }
  3004. public RubyClass getThreadGroup() {
  3005. return threadGroupClass;
  3006. }
  3007. void setThreadGroup(RubyClass threadGroupClass) {
  3008. this.threadGroupClass = threadGroupClass;
  3009. }
  3010. public RubyThreadGroup getDefaultThreadGroup() {
  3011. return defaultThreadGroup;
  3012. }
  3013. void setDefaultThreadGroup(RubyThreadGroup defaultThreadGroup) {
  3014. this.defaultThreadGroup = defaultThreadGroup;
  3015. }
  3016. public RubyClass getContinuation() {
  3017. return continuationClass;
  3018. }
  3019. void setContinuation(RubyClass continuationClass) {
  3020. this.continuationClass = continuationClass;
  3021. }
  3022. public RubyClass getStructClass() {
  3023. return structClass;
  3024. }
  3025. void setStructClass(RubyClass structClass) {
  3026. this.structClass = structClass;
  3027. }
  3028. public IRubyObject getTmsStruct() {
  3029. return tmsStruct;
  3030. }
  3031. void setTmsStruct(RubyClass tmsStruct) {
  3032. this.tmsStruct = tmsStruct;
  3033. }
  3034. public IRubyObject getPasswdStruct() {
  3035. return passwdStruct;
  3036. }
  3037. void setPasswdStruct(RubyClass passwdStruct) {
  3038. this.passwdStruct = passwdStruct;
  3039. }
  3040. public IRubyObject getGroupStruct() {
  3041. return groupStruct;
  3042. }
  3043. void setGroupStruct(RubyClass groupStruct) {
  3044. this.groupStruct = groupStruct;
  3045. }
  3046. public RubyModule getGC() {
  3047. return gcModule;
  3048. }
  3049. void setGC(RubyModule gcModule) {
  3050. this.gcModule = gcModule;
  3051. }
  3052. public RubyModule getObjectSpaceModule() {
  3053. return objectSpaceModule;
  3054. }
  3055. void setObjectSpaceModule(RubyModule objectSpaceModule) {
  3056. this.objectSpaceModule = objectSpaceModule;
  3057. }
  3058. public RubyModule getProcess() {
  3059. return processModule;
  3060. }
  3061. void setProcess(RubyModule processModule) {
  3062. this.processModule = processModule;
  3063. }
  3064. public RubyClass getProcStatus() {
  3065. return procStatusClass;
  3066. }
  3067. void setProcStatus(RubyClass procStatusClass) {
  3068. this.procStatusClass = procStatusClass;
  3069. }
  3070. public RubyModule getProcUID() {
  3071. return procUIDModule;
  3072. }
  3073. void setProcUID(RubyModule procUIDModule) {
  3074. this.procUIDModule = procUIDModule;
  3075. }
  3076. public RubyModule getProcGID() {
  3077. return procGIDModule;
  3078. }
  3079. void setProcGID(RubyModule procGIDModule) {
  3080. this.procGIDModule = procGIDModule;
  3081. }
  3082. public RubyModule getProcSysModule() {
  3083. return procSysModule;
  3084. }
  3085. void setProcSys(RubyModule procSysModule) {
  3086. this.procSysModule = procSysModule;
  3087. }
  3088. public RubyModule getPrecision() {
  3089. return precisionModule;
  3090. }
  3091. void setPrecision(RubyModule precisionModule) {
  3092. this.precisionModule = precisionModule;
  3093. }
  3094. public RubyModule getErrno() {
  3095. return errnoModule;
  3096. }
  3097. public RubyClass getException() {
  3098. return exceptionClass;
  3099. }
  3100. void setException(RubyClass exceptionClass) {
  3101. this.exceptionClass = exceptionClass;
  3102. }
  3103. public RubyClass getNameError() {
  3104. return nameError;
  3105. }
  3106. public RubyClass getNameErrorMessage() {
  3107. return nameErrorMessage;
  3108. }
  3109. public RubyClass getNoMethodError() {
  3110. return noMethodError;
  3111. }
  3112. public RubyClass getSignalException() {
  3113. return signalException;
  3114. }
  3115. public RubyClass getRangeError() {
  3116. return rangeError;
  3117. }
  3118. public RubyClass getSystemExit() {
  3119. return systemExit;
  3120. }
  3121. public RubyClass getLocalJumpError() {
  3122. return localJumpError;
  3123. }
  3124. public RubyClass getNativeException() {
  3125. return nativeException;
  3126. }
  3127. public RubyClass getSystemCallError() {
  3128. return systemCallError;
  3129. }
  3130. public RubyClass getFatal() {
  3131. return fatal;
  3132. }
  3133. public RubyClass getInterrupt() {
  3134. return interrupt;
  3135. }
  3136. public RubyClass getTypeError() {
  3137. return typeError;
  3138. }
  3139. public RubyClass getArgumentError() {
  3140. return argumentError;
  3141. }
  3142. public RubyClass getIndexError() {
  3143. return indexError;
  3144. }
  3145. public RubyClass getSyntaxError() {
  3146. return syntaxError;
  3147. }
  3148. public RubyClass getStandardError() {
  3149. return standardError;
  3150. }
  3151. public RubyClass getRuntimeError() {
  3152. return runtimeError;
  3153. }
  3154. public RubyClass getIOError() {
  3155. return ioError;
  3156. }
  3157. public RubyClass getLoadError() {
  3158. return loadError;
  3159. }
  3160. public RubyClass getNotImplementedError() {
  3161. return notImplementedError;
  3162. }
  3163. public RubyClass getSecurityError() {
  3164. return securityError;
  3165. }
  3166. public RubyClass getNoMemoryError() {
  3167. return noMemoryError;
  3168. }
  3169. public RubyClass getRegexpError() {
  3170. return regexpError;
  3171. }
  3172. public RubyClass getEOFError() {
  3173. return eofError;
  3174. }
  3175. public RubyClass getThreadError() {
  3176. return threadError;
  3177. }
  3178. public RubyClass getConcurrencyError() {
  3179. return concurrencyError;
  3180. }
  3181. public RubyClass getSystemStackError() {
  3182. return systemStackError;
  3183. }
  3184. public RubyClass getZeroDivisionError() {
  3185. return zeroDivisionError;
  3186. }
  3187. public RubyClass getFloatDomainError() {
  3188. return floatDomainError;
  3189. }
  3190. private RubyHash charsetMap;
  3191. public RubyHash getCharsetMap() {
  3192. if (charsetMap == null) charsetMap = new RubyHash(this);
  3193. return charsetMap;
  3194. }
  3195. /** Getter for property isVerbose.
  3196. * @return Value of property isVerbose.
  3197. */
  3198. public IRubyObject getVerbose() {
  3199. return verbose;
  3200. }
  3201. /** Setter for property isVerbose.
  3202. * @param verbose New value of property isVerbose.
  3203. */
  3204. public void setVerbose(IRubyObject verbose) {
  3205. this.verbose = verbose;
  3206. }
  3207. /** Getter for property isDebug.
  3208. * @return Value of property isDebug.
  3209. */
  3210. public IRubyObject getDebug() {
  3211. return debug;
  3212. }
  3213. /** Setter for property isDebug.
  3214. * @param debug New value of property isDebug.
  3215. */
  3216. public void setDebug(IRubyObject debug) {
  3217. this.debug = debug;
  3218. }
  3219. public JavaSupport getJavaSupport() {
  3220. return javaSupport;
  3221. }
  3222. public static ClassLoader getClassLoader() {
  3223. // we try to get the classloader that loaded JRuby, falling back on System
  3224. ClassLoader loader = Ruby.class.getClassLoader();
  3225. if (loader == null) {
  3226. loader = ClassLoader.getSystemClassLoader();
  3227. }
  3228. return loader;
  3229. }
  3230. public synchronized JRubyClassLoader getJRubyClassLoader() {
  3231. // FIXME: Get rid of laziness and handle restricted access elsewhere
  3232. if (!Ruby.isSecurityRestricted() && jrubyClassLoader == null) {
  3233. jrubyClassLoader = new JRubyClassLoader(config.getLoader());
  3234. }
  3235. return jrubyClassLoader;
  3236. }
  3237. /** Defines a global variable
  3238. */
  3239. public void defineVariable(final GlobalVariable variable) {
  3240. globalVariables.define(variable.name(), new IAccessor() {
  3241. public IRubyObject getValue() {
  3242. return variable.get();
  3243. }
  3244. public IRubyObject setValue(IRubyObject newValue) {
  3245. return variable.set(newValue);
  3246. }
  3247. });
  3248. }
  3249. /** defines a readonly global variable
  3250. *
  3251. */
  3252. public void defineReadonlyVariable(String name, IRubyObject value) {
  3253. globalVariables.defineReadonly(name, new ValueAccessor(value));
  3254. }
  3255. public Node parseFile(InputStream in, String file, DynamicScope scope) {
  3256. return parser.parse(file, in, scope, new ParserConfiguration(0, false, false, true));
  3257. }
  3258. public Node parseInline(InputStream in, String file, DynamicScope scope) {
  3259. return parser.parse(file, in, scope, new ParserConfiguration(0, false, true));
  3260. }
  3261. public Node parseEval(String content, String file, DynamicScope scope, int lineNumber) {
  3262. byte[] bytes;
  3263. try {
  3264. bytes = content.getBytes(KCode.NONE.getKCode());
  3265. } catch (UnsupportedEncodingException e) {
  3266. bytes = content.getBytes();
  3267. }
  3268. return parser.parse(file, new ByteArrayInputStream(bytes), scope,
  3269. new ParserConfiguration(lineNumber, false));
  3270. }
  3271. public Node parse(String content, String file, DynamicScope scope, int lineNumber,
  3272. boolean extraPositionInformation) {
  3273. byte[] bytes;
  3274. try {
  3275. bytes = content.getBytes(KCode.NONE.getKCode());
  3276. } catch (UnsupportedEncodingException e) {
  3277. bytes = content.getBytes();
  3278. }
  3279. return parser.parse(file, new ByteArrayInputStream(bytes), scope,
  3280. new ParserConfiguration(lineNumber, extraPositionInformation, false));
  3281. }
  3282. public Node parseEval(ByteList content, String file, DynamicScope scope, int lineNumber) {
  3283. return parser.parse(file, content, scope, new ParserConfiguration(lineNumber, false));
  3284. }
  3285. public Node parse(ByteList content, String file, DynamicScope scope, int lineNumber,
  3286. boolean extraPositionInformation) {
  3287. return parser.parse(file, content, scope,
  3288. new ParserConfiguration(lineNumber, extraPositionInformation, false));
  3289. }
  3290. public ThreadService getThreadService() {
  3291. return threadService;
  3292. }
  3293. public ThreadContext getCurrentContext() {
  3294. return threadService.getCurrentContext();
  3295. }
  3296. /**
  3297. * Returns the loadService.
  3298. * @return ILoadService
  3299. */
  3300. public LoadService getLoadService() {
  3301. return loadService;
  3302. }
  3303. public RubyWarnings getWarnings() {
  3304. return warnings;
  3305. }
  3306. public PrintStream getErrorStream() {
  3307. // FIXME: We can't guarantee this will always be a RubyIO...so the old code here is not safe
  3308. /*java.io.OutputStream os = ((RubyIO) getGlobalVariables().get("$stderr")).getOutStream();
  3309. if(null != os) {
  3310. return new PrintStream(os);
  3311. } else {
  3312. return new PrintStream(new org.jruby.util.SwallowingOutputStream());
  3313. }*/
  3314. return new PrintStream(new IOOutputStream(getGlobalVariables().get("$stderr")));
  3315. }
  3316. public InputStream getInputStream() {
  3317. return new IOInputStream(getGlobalVariables().get("$stdin"));
  3318. }
  3319. public PrintStream getOutputStream() {
  3320. return new PrintStream(new IOOutputStream(getGlobalVariables().get("$stdout")));
  3321. }
  3322. public RubyModule getClassFromPath(String path) {
  3323. RubyModule c = getObject();
  3324. if (path.length() == 0 || path.charAt(0) == '#') {
  3325. throw newTypeError("can't retrieve anonymous class " + path);
  3326. }
  3327. int pbeg = 0, p = 0;
  3328. for(int l=path.length(); p<l; ) {
  3329. while(p<l && path.charAt(p) != ':') {
  3330. p++;
  3331. }
  3332. String str = path.substring(pbeg, p);
  3333. if(p<l && path.charAt(p) == ':') {
  3334. if(p+1 < l && path.charAt(p+1) != ':') {
  3335. throw newTypeError("undefined class/module " + path.substring(pbeg,p));
  3336. }
  3337. p += 2;
  3338. pbeg = p;
  3339. }
  3340. IRubyObject cc = c.getConstant(str);
  3341. if(!(cc instanceof RubyModule)) {
  3342. throw newTypeError("" + path + " does not refer to class/module");
  3343. }
  3344. c = (RubyModule)cc;
  3345. }
  3346. return c;
  3347. }
  3348. /** Prints an error with backtrace to the error stream.
  3349. *
  3350. * MRI: eval.c - error_print()
  3351. *
  3352. */
  3353. public void printError(RubyException excp) {
  3354. if (excp == null || excp.isNil()) {
  3355. return;
  3356. }
  3357. ThreadContext context = getCurrentContext();
  3358. IRubyObject backtrace = excp.callMethod(context, "backtrace");
  3359. PrintStream errorStream = getErrorStream();
  3360. if (backtrace.isNil() || !(backtrace instanceof RubyArray)) {
  3361. if (context.getFile() != null) {
  3362. errorStream.print(context.getFile() + ":" + context.getLine());
  3363. } else {
  3364. errorStream.print(context.getLine());
  3365. }
  3366. } else if (((RubyArray) backtrace).getLength() == 0) {
  3367. printErrorPos(context, errorStream);
  3368. } else {
  3369. IRubyObject mesg = ((RubyArray) backtrace).first();
  3370. if (mesg.isNil()) {
  3371. printErrorPos(context, errorStream);
  3372. } else {
  3373. errorStream.print(mesg);
  3374. }
  3375. }
  3376. RubyClass type = excp.getMetaClass();
  3377. String info = excp.toString();
  3378. if (type == getRuntimeError() && (info == null || info.length() == 0)) {
  3379. errorStream.print(": unhandled exception\n");
  3380. } else {
  3381. String path = type.getName();
  3382. if (info.length() == 0) {
  3383. errorStream.print(": " + path + '\n');
  3384. } else {
  3385. if (path.startsWith("#")) {
  3386. path = null;
  3387. }
  3388. String tail = null;
  3389. if (info.indexOf("\n") != -1) {
  3390. tail = info.substring(info.indexOf("\n") + 1);
  3391. info = info.substring(0, info.indexOf("\n"));
  3392. }
  3393. errorStream.print(": " + info);
  3394. if (path != null) {
  3395. errorStream.print(" (" + path + ")\n");
  3396. }
  3397. if (tail != null) {
  3398. errorStream.print(tail + '\n');
  3399. }
  3400. }
  3401. }
  3402. excp.printBacktrace(errorStream);
  3403. }
  3404. private void printErrorPos(ThreadContext context, PrintStream errorStream) {
  3405. if (context.getFile() != null) {
  3406. if (context.getFrameName() != null) {
  3407. errorStream.print(context.getFile() + ":" + context.getLine());
  3408. errorStream.print(":in '" + context.getFrameName() + '\'');
  3409. } else if (context.getLine() != 0) {
  3410. errorStream.print(context.getFile() + ":" + context.getLine());
  3411. } else {
  3412. errorStream.print(context.getFile());
  3413. }
  3414. }
  3415. }
  3416. public void loadFile(String scriptName, InputStream in, boolean wrap) {
  3417. IRubyObject self = wrap ? TopSelfFactory.createTopSelf(this) : getTopSelf();
  3418. ThreadContext context = getCurrentContext();
  3419. String file = context.getFile();
  3420. try {
  3421. secure(4); /* should alter global state */
  3422. context.setFile(scriptName);
  3423. context.preNodeEval(objectClass, self, scriptName);
  3424. parseFile(in, scriptName, null).interpret(this, context, self, Block.NULL_BLOCK);
  3425. } catch (JumpException.ReturnJump rj) {
  3426. return;
  3427. } finally {
  3428. context.postNodeEval();
  3429. context.setFile(file);
  3430. }
  3431. }
  3432. public void compileAndLoadFile(String filename, InputStream in, boolean wrap) {
  3433. IRubyObject self = wrap ? TopSelfFactory.createTopSelf(this) : getTopSelf();
  3434. ThreadContext context = getCurrentContext();
  3435. String file = context.getFile();
  3436. try {
  3437. secure(4); /* should alter global state */
  3438. context.setFile(filename);
  3439. context.preNodeEval(objectClass, self, filename);
  3440. Node scriptNode = parseFile(in, filename, null);
  3441. Script script = tryCompile(scriptNode, new JRubyClassLoader(jrubyClassLoader));
  3442. if (script == null) {
  3443. System.err.println("Error, could not compile; pass -J-Djruby.jit.logging.verbose=true for more details");
  3444. }
  3445. runScript(script);
  3446. } catch (JumpException.ReturnJump rj) {
  3447. return;
  3448. } finally {
  3449. context.postNodeEval();
  3450. context.setFile(file);
  3451. }
  3452. }
  3453. public void loadScript(Script script) {
  3454. IRubyObject self = getTopSelf();
  3455. ThreadContext context = getCurrentContext();
  3456. try {
  3457. secure(4); /* should alter global state */
  3458. context.preNodeEval(objectClass, self);
  3459. script.load(context, self, IRubyObject.NULL_ARRAY, Block.NULL_BLOCK);
  3460. } catch (JumpException.ReturnJump rj) {
  3461. return;
  3462. } finally {
  3463. context.postNodeEval();
  3464. }
  3465. }
  3466. public class CallTraceFuncHook extends EventHook {
  3467. private RubyProc traceFunc;
  3468. public void setTraceFunc(RubyProc traceFunc) {
  3469. this.traceFunc = traceFunc;
  3470. }
  3471. public void eventHandler(ThreadContext context, String eventName, String file, int line, String name, IRubyObject type) {
  3472. if (!context.isWithinTrace()) {
  3473. if (file == null) file = "(ruby)";
  3474. if (type == null) type = getFalse();
  3475. RubyBinding binding = RubyBinding.newBinding(Ruby.this);
  3476. context.preTrace();
  3477. try {
  3478. traceFunc.call(context, new IRubyObject[] {
  3479. newString(eventName), // event name
  3480. newString(file), // filename
  3481. newFixnum(line), // line numbers should be 1-based
  3482. name != null ? newSymbol(name) : getNil(),
  3483. binding,
  3484. type
  3485. });
  3486. } finally {
  3487. context.postTrace();
  3488. }
  3489. }
  3490. }
  3491. public boolean isInterestedInEvent(RubyEvent event) {
  3492. return true;
  3493. }
  3494. };
  3495. private final CallTraceFuncHook callTraceFuncHook = new CallTraceFuncHook();
  3496. public void addEventHook(EventHook hook) {
  3497. eventHooks.add(hook);
  3498. hasEventHooks = true;
  3499. }
  3500. public void removeEventHook(EventHook hook) {
  3501. eventHooks.remove(hook);
  3502. hasEventHooks = !eventHooks.isEmpty();
  3503. }
  3504. public void setTraceFunction(RubyProc traceFunction) {
  3505. removeEventHook(callTraceFuncHook);
  3506. if (traceFunction == null) {
  3507. return;
  3508. }
  3509. callTraceFuncHook.setTraceFunc(traceFunction);
  3510. addEventHook(callTraceFuncHook);
  3511. }
  3512. public void callEventHooks(ThreadContext context, RubyEvent event, String file, int line, String name, IRubyObject type) {
  3513. for (EventHook eventHook : eventHooks) {
  3514. if (eventHook.isInterestedInEvent(event)) {
  3515. eventHook.event(context, event, file, line, name, type);
  3516. }
  3517. }
  3518. }
  3519. public boolean hasEventHooks() {
  3520. return hasEventHooks;
  3521. }
  3522. public GlobalVariables getGlobalVariables() {
  3523. return globalVariables;
  3524. }
  3525. // For JSR 223 support: see http://scripting.java.net/
  3526. public void setGlobalVariables(GlobalVariables globalVariables) {
  3527. this.globalVariables = globalVariables;
  3528. }
  3529. public CallbackFactory callbackFactory(Class<?> type) {
  3530. return CallbackFactory.createFactory(this, type);
  3531. }
  3532. /**
  3533. * Push block onto exit stack. When runtime environment exits
  3534. * these blocks will be evaluated.
  3535. *
  3536. * @return the element that was pushed onto stack
  3537. */
  3538. public IRubyObject pushExitBlock(RubyProc proc) {
  3539. atExitBlocks.push(proc);
  3540. return proc;
  3541. }
  3542. // use this for JRuby-internal finalizers
  3543. public void addInternalFinalizer(Finalizable finalizer) {
  3544. synchronized (internalFinalizersMutex) {
  3545. if (internalFinalizers == null) {
  3546. internalFinalizers = new WeakHashMap<Finalizable, Object>();
  3547. }
  3548. internalFinalizers.put(finalizer, null);
  3549. }
  3550. }
  3551. // this method is for finalizers registered via ObjectSpace
  3552. public void addFinalizer(Finalizable finalizer) {
  3553. synchronized (finalizersMutex) {
  3554. if (finalizers == null) {
  3555. finalizers = new WeakHashMap<Finalizable, Object>();
  3556. }
  3557. finalizers.put(finalizer, null);
  3558. }
  3559. }
  3560. public void removeInternalFinalizer(Finalizable finalizer) {
  3561. synchronized (internalFinalizersMutex) {
  3562. if (internalFinalizers != null) {
  3563. internalFinalizers.remove(finalizer);
  3564. }
  3565. }
  3566. }
  3567. public void removeFinalizer(Finalizable finalizer) {
  3568. synchronized (finalizersMutex) {
  3569. if (finalizers != null) {
  3570. finalizers.remove(finalizer);
  3571. }
  3572. }
  3573. }
  3574. /**
  3575. * Make sure Kernel#at_exit procs get invoked on runtime shutdown.
  3576. * This method needs to be explicitly called to work properly.
  3577. * I thought about using finalize(), but that did not work and I
  3578. * am not sure the runtime will be at a state to run procs by the
  3579. * time Ruby is going away. This method can contain any other
  3580. * things that need to be cleaned up at shutdown.
  3581. */
  3582. public void tearDown() {
  3583. int status = 0;
  3584. while (!atExitBlocks.empty()) {
  3585. RubyProc proc = atExitBlocks.pop();
  3586. try {
  3587. proc.call(getCurrentContext(), IRubyObject.NULL_ARRAY);
  3588. } catch (RaiseException rj) {
  3589. RubyException raisedException = rj.getException();
  3590. if (!getSystemExit().isInstance(raisedException)) {
  3591. status = 1;
  3592. printError(raisedException);
  3593. } else {
  3594. IRubyObject statusObj = raisedException.callMethod(
  3595. getCurrentContext(), "status");
  3596. if (statusObj != null && !statusObj.isNil()) {
  3597. status = RubyNumeric.fix2int(statusObj);
  3598. }
  3599. }
  3600. }
  3601. }
  3602. if (finalizers != null) {
  3603. synchronized (finalizers) {
  3604. for (Iterator<Finalizable> finalIter = new ArrayList<Finalizable>(finalizers.keySet()).iterator(); finalIter.hasNext();) {
  3605. finalIter.next().finalize();
  3606. finalIter.remove();
  3607. }
  3608. }
  3609. }
  3610. synchronized (internalFinalizersMutex) {
  3611. if (internalFinalizers != null) {
  3612. for (Iterator<Finalizable> finalIter = new ArrayList<Finalizable>(
  3613. internalFinalizers.keySet()).iterator(); finalIter.hasNext();) {
  3614. finalIter.next().finalize();
  3615. finalIter.remove();
  3616. }
  3617. }
  3618. }
  3619. getThreadService().disposeCurrentThread();
  3620. getBeanManager().unregisterCompiler();
  3621. getBeanManager().unregisterConfig();
  3622. getBeanManager().unregisterClassCache();
  3623. getBeanManager().unregisterMethodCache();
  3624. if (status != 0) {
  3625. throw newSystemExit(status);
  3626. }
  3627. }
  3628. // new factory methods ------------------------------------------------------------------------
  3629. public RubyArray newEmptyArray() {
  3630. return RubyArray.newEmptyArray(this);
  3631. }
  3632. public RubyArray newArray() {
  3633. return RubyArray.newArray(this);
  3634. }
  3635. public RubyArray newArrayLight() {
  3636. return RubyArray.newArrayLight(this);
  3637. }
  3638. public RubyArray newArray(IRubyObject object) {
  3639. return RubyArray.newArray(this, object);
  3640. }
  3641. public RubyArray newArray(IRubyObject car, IRubyObject cdr) {
  3642. return RubyArray.newArray(this, car, cdr);
  3643. }
  3644. public RubyArray newArray(IRubyObject[] objects) {
  3645. return RubyArray.newArray(this, objects);
  3646. }
  3647. public RubyArray newArrayNoCopy(IRubyObject[] objects) {
  3648. return RubyArray.newArrayNoCopy(this, objects);
  3649. }
  3650. public RubyArray newArrayNoCopyLight(IRubyObject[] objects) {
  3651. return RubyArray.newArrayNoCopyLight(this, objects);
  3652. }
  3653. public RubyArray newArray(List<IRubyObject> list) {
  3654. return RubyArray.newArray(this, list);
  3655. }
  3656. public RubyArray newArray(int size) {
  3657. return RubyArray.newArray(this, size);
  3658. }
  3659. public RubyBoolean newBoolean(boolean value) {
  3660. return RubyBoolean.newBoolean(this, value);
  3661. }
  3662. public RubyFileStat newFileStat(String filename, boolean lstat) {
  3663. return RubyFileStat.newFileStat(this, filename, lstat);
  3664. }
  3665. public RubyFileStat newFileStat(FileDescriptor descriptor) {
  3666. return RubyFileStat.newFileStat(this, descriptor);
  3667. }
  3668. public RubyFixnum newFixnum(long value) {
  3669. return RubyFixnum.newFixnum(this, value);
  3670. }
  3671. public RubyFixnum newFixnum(int value) {
  3672. return RubyFixnum.newFixnum(this, value);
  3673. }
  3674. public RubyFloat newFloat(double value) {
  3675. return RubyFloat.newFloat(this, value);
  3676. }
  3677. public RubyNumeric newNumeric() {
  3678. return RubyNumeric.newNumeric(this);
  3679. }
  3680. public RubyProc newProc(Block.Type type, Block block) {
  3681. if (type != Block.Type.LAMBDA && block.getProcObject() != null) return block.getProcObject();
  3682. RubyProc proc = RubyProc.newProc(this, type);
  3683. proc.callInit(IRubyObject.NULL_ARRAY, block);
  3684. return proc;
  3685. }
  3686. public RubyProc newBlockPassProc(Block.Type type, Block block) {
  3687. if (type != Block.Type.LAMBDA && block.getProcObject() != null) return block.getProcObject();
  3688. RubyProc proc = RubyProc.newProc(this, type);
  3689. proc.initialize(getCurrentContext(), block);
  3690. return proc;
  3691. }
  3692. public RubyBinding newBinding() {
  3693. return RubyBinding.newBinding(this);
  3694. }
  3695. public RubyBinding newBinding(Binding binding) {
  3696. return RubyBinding.newBinding(this, binding);
  3697. }
  3698. public RubyString newString() {
  3699. return RubyString.newString(this, new ByteList());
  3700. }
  3701. public RubyString newString(String string) {
  3702. return RubyString.newString(this, string);
  3703. }
  3704. public RubyString newString(ByteList byteList) {
  3705. return RubyString.newString(this, byteList);
  3706. }
  3707. @Deprecated
  3708. public RubyString newStringShared(ByteList byteList) {
  3709. return RubyString.newStringShared(this, byteList);
  3710. }
  3711. public RubySymbol newSymbol(String name) {
  3712. return symbolTable.getSymbol(name);
  3713. }
  3714. /**
  3715. * Faster than {@link #newSymbol(String)} if you already have an interned
  3716. * name String. Don't intern your string just to call this version - the
  3717. * overhead of interning will more than wipe out any benefit from the faster
  3718. * lookup.
  3719. *
  3720. * @param internedName the symbol name, <em>must</em> be interned! if in
  3721. * doubt, call {@link #newSymbol(String)} instead.
  3722. * @return the symbol for name
  3723. */
  3724. public RubySymbol fastNewSymbol(String internedName) {
  3725. assert internedName == internedName.intern() : internedName + " is not interned";
  3726. return symbolTable.fastGetSymbol(internedName);
  3727. }
  3728. public RubyTime newTime(long milliseconds) {
  3729. return RubyTime.newTime(this, milliseconds);
  3730. }
  3731. public RaiseException newRuntimeError(String message) {
  3732. return newRaiseException(getRuntimeError(), message);
  3733. }
  3734. public RaiseException newArgumentError(String message) {
  3735. return newRaiseException(getArgumentError(), message);
  3736. }
  3737. public RaiseException newArgumentError(int got, int expected) {
  3738. return newRaiseException(getArgumentError(), "wrong # of arguments(" + got + " for " + expected + ")");
  3739. }
  3740. public RaiseException newErrnoEBADFError() {
  3741. return newRaiseException(getErrno().fastGetClass("EBADF"), "Bad file descriptor");
  3742. }
  3743. public RaiseException newErrnoENOPROTOOPTError() {
  3744. return newRaiseException(getErrno().fastGetClass("ENOPROTOOPT"), "Protocol not available");
  3745. }
  3746. public RaiseException newErrnoEPIPEError() {
  3747. return newRaiseException(getErrno().fastGetClass("EPIPE"), "Broken pipe");
  3748. }
  3749. public RaiseException newErrnoECONNREFUSEDError() {
  3750. return newRaiseException(getErrno().fastGetClass("ECONNREFUSED"), "Connection refused");
  3751. }
  3752. public RaiseException newErrnoECONNRESETError() {
  3753. return newRaiseException(getErrno().fastGetClass("ECONNRESET"), "Connection reset by peer");
  3754. }
  3755. public RaiseException newErrnoEADDRINUSEError() {
  3756. return newRaiseException(getErrno().fastGetClass("EADDRINUSE"), "Address in use");
  3757. }
  3758. public RaiseException newErrnoEINVALError() {
  3759. return newRaiseException(getErrno().fastGetClass("EINVAL"), "Invalid file");
  3760. }
  3761. public RaiseException newErrnoENOENTError() {
  3762. return newRaiseException(getErrno().fastGetClass("ENOENT"), "File not found");
  3763. }
  3764. public RaiseException newErrnoEACCESError(String message) {
  3765. return newRaiseException(getErrno().fastGetClass("EACCES"), message);
  3766. }
  3767. public RaiseException newErrnoEAGAINError(String message) {
  3768. return newRaiseException(getErrno().fastGetClass("EAGAIN"), message);
  3769. }
  3770. public RaiseException newErrnoEISDirError() {
  3771. return newRaiseException(getErrno().fastGetClass("EISDIR"), "Is a directory");
  3772. }
  3773. public RaiseException newErrnoESPIPEError() {
  3774. return newRaiseException(getErrno().fastGetClass("ESPIPE"), "Illegal seek");
  3775. }
  3776. public RaiseException newErrnoEBADFError(String message) {
  3777. return newRaiseException(getErrno().fastGetClass("EBADF"), message);
  3778. }
  3779. public RaiseException newErrnoEINVALError(String message) {
  3780. return newRaiseException(getErrno().fastGetClass("EINVAL"), message);
  3781. }
  3782. public RaiseException newErrnoENOTDIRError(String message) {
  3783. return newRaiseException(getErrno().fastGetClass("ENOTDIR"), message);
  3784. }
  3785. public RaiseException newErrnoENOTSOCKError(String message) {
  3786. return newRaiseException(getErrno().fastGetClass("ENOTSOCK"), message);
  3787. }
  3788. public RaiseException newErrnoENOENTError(String message) {
  3789. return newRaiseException(getErrno().fastGetClass("ENOENT"), message);
  3790. }
  3791. public RaiseException newErrnoESPIPEError(String message) {
  3792. return newRaiseException(getErrno().fastGetClass("ESPIPE"), message);
  3793. }
  3794. public RaiseException newErrnoEEXISTError(String message) {
  3795. return newRaiseException(getErrno().fastGetClass("EEXIST"), message);
  3796. }
  3797. public RaiseException newErrnoEDOMError(String message) {
  3798. return newRaiseException(getErrno().fastGetClass("EDOM"), "Domain error - " + message);
  3799. }
  3800. public RaiseException newErrnoECHILDError() {
  3801. return newRaiseException(getErrno().fastGetClass("ECHILD"), "No child processes");
  3802. }
  3803. public RaiseException newIndexError(String message) {
  3804. return newRaiseException(getIndexError(), message);
  3805. }
  3806. public RaiseException newSecurityError(String message) {
  3807. return newRaiseException(getSecurityError(), message);
  3808. }
  3809. public RaiseException newSystemCallError(String message) {
  3810. return newRaiseException(getSystemCallError(), message);
  3811. }
  3812. public RaiseException newTypeError(String message) {
  3813. return newRaiseException(getTypeError(), message);
  3814. }
  3815. public RaiseException newThreadError(String message) {
  3816. return newRaiseException(getThreadError(), message);
  3817. }
  3818. public RaiseException newConcurrencyError(String message) {
  3819. return newRaiseException(getConcurrencyError(), message);
  3820. }
  3821. public RaiseException newSyntaxError(String message) {
  3822. return newRaiseException(getSyntaxError(), message);
  3823. }
  3824. public RaiseException newRegexpError(String message) {
  3825. return newRaiseException(getRegexpError(), message);
  3826. }
  3827. public RaiseException newRangeError(String message) {
  3828. return newRaiseException(getRangeError(), message);
  3829. }
  3830. public RaiseException newNotImplementedError(String message) {
  3831. return newRaiseException(getNotImplementedError(), message);
  3832. }
  3833. public RaiseException newInvalidEncoding(String message) {
  3834. return newRaiseException(fastGetClass("Iconv").fastGetClass("InvalidEncoding"), message);
  3835. }
  3836. public RaiseException newNoMethodError(String message, String name, IRubyObject args) {
  3837. return new RaiseException(new RubyNoMethodError(this, getNoMethodError(), message, name, args), true);
  3838. }
  3839. public RaiseException newNameError(String message, String name) {
  3840. return newNameError(message, name, null);
  3841. }
  3842. public RaiseException newNameError(String message, String name, Throwable origException) {
  3843. return newNameError(message, name, origException, true);
  3844. }
  3845. public RaiseException newNameError(String message, String name, Throwable origException, boolean printWhenVerbose) {
  3846. if (printWhenVerbose && origException != null && this.getVerbose().isTrue()) {
  3847. origException.printStackTrace(getErrorStream());
  3848. }
  3849. return new RaiseException(new RubyNameError(
  3850. this, getNameError(), message, name), true);
  3851. }
  3852. public RaiseException newLocalJumpError(String reason, IRubyObject exitValue, String message) {
  3853. return new RaiseException(new RubyLocalJumpError(this, getLocalJumpError(), message, reason, exitValue), true);
  3854. }
  3855. public RaiseException newRedoLocalJumpError() {
  3856. return new RaiseException(new RubyLocalJumpError(this, getLocalJumpError(), "unexpected redo", "redo", getNil()), true);
  3857. }
  3858. public RaiseException newLoadError(String message) {
  3859. return newRaiseException(getLoadError(), message);
  3860. }
  3861. public RaiseException newFrozenError(String objectType) {
  3862. // TODO: Should frozen error have its own distinct class? If not should more share?
  3863. return newRaiseException(getTypeError(), "can't modify frozen " + objectType);
  3864. }
  3865. public RaiseException newSystemStackError(String message) {
  3866. return newRaiseException(getSystemStackError(), message);
  3867. }
  3868. public RaiseException newSystemExit(int status) {
  3869. return new RaiseException(RubySystemExit.newInstance(this, status));
  3870. }
  3871. public RaiseException newIOError(String message) {
  3872. return newRaiseException(getIOError(), message);
  3873. }
  3874. public RaiseException newStandardError(String message) {
  3875. return newRaiseException(getStandardError(), message);
  3876. }
  3877. public RaiseException newIOErrorFromException(IOException ioe) {
  3878. // TODO: this is kinda gross
  3879. if(ioe.getMessage() != null) {
  3880. if (ioe.getMessage().equals("Broken pipe")) {
  3881. throw newErrnoEPIPEError();
  3882. } else if (ioe.getMessage().equals("Connection reset by peer")) {
  3883. throw newErrnoECONNRESETError();
  3884. }
  3885. return newRaiseException(getIOError(), ioe.getMessage());
  3886. } else {
  3887. return newRaiseException(getIOError(), "IO Error");
  3888. }
  3889. }
  3890. public RaiseException newTypeError(IRubyObject receivedObject, RubyClass expectedType) {
  3891. return newRaiseException(getTypeError(), "wrong argument type " +
  3892. receivedObject.getMetaClass().getRealClass() + " (expected " + expectedType + ")");
  3893. }
  3894. public RaiseException newEOFError() {
  3895. return newRaiseException(getEOFError(), "End of file reached");
  3896. }
  3897. public RaiseException newEOFError(String message) {
  3898. return newRaiseException(getEOFError(), message);
  3899. }
  3900. public RaiseException newZeroDivisionError() {
  3901. return newRaiseException(getZeroDivisionError(), "divided by 0");
  3902. }
  3903. public RaiseException newFloatDomainError(String message){
  3904. return newRaiseException(getFloatDomainError(), message);
  3905. }
  3906. /**
  3907. * @param exceptionClass
  3908. * @param message
  3909. * @return
  3910. */
  3911. private RaiseException newRaiseException(RubyClass exceptionClass, String message) {
  3912. RaiseException re = new RaiseException(this, exceptionClass, message, true);
  3913. return re;
  3914. }
  3915. public RubySymbol.SymbolTable getSymbolTable() {
  3916. return symbolTable;
  3917. }
  3918. public void setStackTraces(int stackTraces) {
  3919. this.stackTraces = stackTraces;
  3920. }
  3921. public int getStackTraces() {
  3922. return stackTraces;
  3923. }
  3924. public void setRandomSeed(long randomSeed) {
  3925. this.randomSeed = randomSeed;
  3926. }
  3927. public long getRandomSeed() {
  3928. return randomSeed;
  3929. }
  3930. public Random getRandom() {
  3931. return random;
  3932. }
  3933. public ObjectSpace getObjectSpace() {
  3934. return objectSpace;
  3935. }
  3936. public Map<Integer, WeakReference<ChannelDescriptor>> getDescriptors() {
  3937. return descriptors;
  3938. }
  3939. public long incrementRandomSeedSequence() {
  3940. return randomSeedSequence++;
  3941. }
  3942. public InputStream getIn() {
  3943. return in;
  3944. }
  3945. public PrintStream getOut() {
  3946. return out;
  3947. }
  3948. public PrintStream getErr() {
  3949. return err;
  3950. }
  3951. public boolean isGlobalAbortOnExceptionEnabled() {
  3952. return globalAbortOnExceptionEnabled;
  3953. }
  3954. public void setGlobalAbortOnExceptionEnabled(boolean enable) {
  3955. globalAbortOnExceptionEnabled = enable;
  3956. }
  3957. public boolean isDoNotReverseLookupEnabled() {
  3958. return doNotReverseLookupEnabled;
  3959. }
  3960. public void setDoNotReverseLookupEnabled(boolean b) {
  3961. doNotReverseLookupEnabled = b;
  3962. }
  3963. private ThreadLocal<Map<Object, Object>> inspect = new ThreadLocal<Map<Object, Object>>();
  3964. public void registerInspecting(Object obj) {
  3965. Map<Object, Object> val = inspect.get();
  3966. if (val == null) inspect.set(val = new IdentityHashMap<Object, Object>());
  3967. val.put(obj, null);
  3968. }
  3969. public boolean isInspecting(Object obj) {
  3970. Map<Object, Object> val = inspect.get();
  3971. return val == null ? false : val.containsKey(obj);
  3972. }
  3973. public void unregisterInspecting(Object obj) {
  3974. Map<Object, Object> val = inspect.get();
  3975. if (val != null ) val.remove(obj);
  3976. }
  3977. public boolean isObjectSpaceEnabled() {
  3978. return objectSpaceEnabled;
  3979. }
  3980. // The method is intentionally not public, since it typically should
  3981. // not be used outside of the core.
  3982. /* package-private */ void setObjectSpaceEnabled(boolean objectSpaceEnabled) {
  3983. this.objectSpaceEnabled = objectSpaceEnabled;
  3984. }
  3985. public long getStartTime() {
  3986. return startTime;
  3987. }
  3988. public Profile getProfile() {
  3989. return profile;
  3990. }
  3991. public String getJRubyHome() {
  3992. return config.getJRubyHome();
  3993. }
  3994. public void setJRubyHome(String home) {
  3995. config.setJRubyHome(home);
  3996. }
  3997. public RubyInstanceConfig getInstanceConfig() {
  3998. return config;
  3999. }
  4000. /** GET_VM_STATE_VERSION */
  4001. public long getGlobalState() {
  4002. synchronized(this) {
  4003. return globalState;
  4004. }
  4005. }
  4006. /** INC_VM_STATE_VERSION */
  4007. public void incGlobalState() {
  4008. synchronized(this) {
  4009. globalState = (globalState+1) & 0x8fffffff;
  4010. }
  4011. }
  4012. public static boolean isSecurityRestricted() {
  4013. return securityRestricted;
  4014. }
  4015. public static void setSecurityRestricted(boolean restricted) {
  4016. securityRestricted = restricted;
  4017. }
  4018. public POSIX getPosix() {
  4019. return posix;
  4020. }
  4021. public void setRecordSeparatorVar(GlobalVariable recordSeparatorVar) {
  4022. this.recordSeparatorVar = recordSeparatorVar;
  4023. }
  4024. public GlobalVariable getRecordSeparatorVar() {
  4025. return recordSeparatorVar;
  4026. }
  4027. public Set<Script> getJittedMethods() {
  4028. return jittedMethods;
  4029. }
  4030. public ExecutorService getExecutor() {
  4031. return executor;
  4032. }
  4033. public Map<String, DateTimeZone> getLocalTimezoneCache() {
  4034. return localTimeZoneCache;
  4035. }
  4036. private final CacheMap cacheMap;
  4037. private final ThreadService threadService;
  4038. private Hashtable<Object, Object> runtimeInformation;
  4039. private POSIX posix;
  4040. private int stackTraces = 0;
  4041. private ObjectSpace objectSpace = new ObjectSpace();
  4042. private final RubySymbol.SymbolTable symbolTable = new RubySymbol.SymbolTable(this);
  4043. private Map<Integer, WeakReference<ChannelDescriptor>> descriptors = new ConcurrentHashMap<Integer, WeakReference<ChannelDescriptor>>();
  4044. private long randomSeed = 0;
  4045. private long randomSeedSequence = 0;
  4046. private Random random = new Random();
  4047. private List<EventHook> eventHooks = new Vector<EventHook>();
  4048. private boolean hasEventHooks;
  4049. private boolean globalAbortOnExceptionEnabled = false;
  4050. private boolean doNotReverseLookupEnabled = false;
  4051. private volatile boolean objectSpaceEnabled;
  4052. private final Set<Script> jittedMethods = Collections.synchronizedSet(new WeakHashSet<Script>());
  4053. private static ThreadLocal<Ruby> currentRuntime = new ThreadLocal<Ruby>();
  4054. private long globalState = 1;
  4055. private int safeLevel = -1;
  4056. // Default objects
  4057. private IRubyObject topSelf;
  4058. private RubyNil nilObject;
  4059. private RubyBoolean trueObject;
  4060. private RubyBoolean falseObject;
  4061. public final RubyFixnum[] fixnumCache = new RubyFixnum[256];
  4062. private IRubyObject verbose;
  4063. private IRubyObject debug;
  4064. private RubyThreadGroup defaultThreadGroup;
  4065. /**
  4066. * All the core classes we keep hard references to. These are here largely
  4067. * so that if someone redefines String or Array we won't start blowing up
  4068. * creating strings and arrays internally. They also provide much faster
  4069. * access than going through normal hash lookup on the Object class.
  4070. */
  4071. private RubyClass
  4072. objectClass, moduleClass, classClass, nilClass, trueClass,
  4073. falseClass, numericClass, floatClass, integerClass, fixnumClass,
  4074. complexClass, rationalClass, enumeratorClass,
  4075. arrayClass, hashClass, rangeClass, stringClass, symbolClass,
  4076. procClass, bindingClass, methodClass, unboundMethodClass,
  4077. matchDataClass, regexpClass, timeClass, bignumClass, dirClass,
  4078. fileClass, fileStatClass, ioClass, threadClass, threadGroupClass,
  4079. continuationClass, structClass, tmsStruct, passwdStruct,
  4080. groupStruct, procStatusClass, exceptionClass, runtimeError, ioError,
  4081. scriptError, nameError, nameErrorMessage, noMethodError, signalException,
  4082. rangeError, dummyClass, systemExit, localJumpError, nativeException,
  4083. systemCallError, fatal, interrupt, typeError, argumentError, indexError,
  4084. syntaxError, standardError, loadError, notImplementedError, securityError, noMemoryError,
  4085. regexpError, eofError, threadError, concurrencyError, systemStackError, zeroDivisionError, floatDomainError;
  4086. /**
  4087. * All the core modules we keep direct references to, for quick access and
  4088. * to ensure they remain available.
  4089. */
  4090. private RubyModule
  4091. kernelModule, comparableModule, enumerableModule, mathModule,
  4092. marshalModule, etcModule, fileTestModule, gcModule,
  4093. objectSpaceModule, processModule, procUIDModule, procGIDModule,
  4094. procSysModule, precisionModule, errnoModule;
  4095. // record separator var, to speed up io ops that use it
  4096. private GlobalVariable recordSeparatorVar;
  4097. // former java.lang.System concepts now internalized for MVM
  4098. private String currentDirectory;
  4099. private long startTime = System.currentTimeMillis();
  4100. private RubyInstanceConfig config;
  4101. private InputStream in;
  4102. private PrintStream out;
  4103. private PrintStream err;
  4104. // Java support
  4105. private JavaSupport javaSupport;
  4106. private JRubyClassLoader jrubyClassLoader;
  4107. // Management/monitoring
  4108. private BeanManager beanManager;
  4109. // Compilation
  4110. private final JITCompiler jitCompiler;
  4111. // Note: this field and the following static initializer
  4112. // must be located be in this order!
  4113. private volatile static boolean securityRestricted = false;
  4114. static {
  4115. if (SafePropertyAccessor.isSecurityProtected("jruby.reflection")) {
  4116. // can't read non-standard properties
  4117. securityRestricted = true;
  4118. } else {
  4119. SecurityManager sm = System.getSecurityManager();
  4120. if (sm != null) {
  4121. try {
  4122. sm.checkCreateClassLoader();
  4123. } catch (SecurityException se) {
  4124. // can't create custom classloaders
  4125. securityRestricted = true;
  4126. }
  4127. }
  4128. }
  4129. }
  4130. private Parser parser = new Parser(this);
  4131. private LoadService loadService;
  4132. private GlobalVariables globalVariables = new GlobalVariables(this);
  4133. private RubyWarnings warnings = new RubyWarnings(this);
  4134. // Contains a list of all blocks (as Procs) that should be called when
  4135. // the runtime environment exits.
  4136. private Stack<RubyProc> atExitBlocks = new Stack<RubyProc>();
  4137. private Profile profile;
  4138. private KCode kcode = KCode.NONE;
  4139. // Atomic integers for symbol and method IDs
  4140. private AtomicInteger symbolLastId = new AtomicInteger(128);
  4141. private AtomicInteger moduleLastId = new AtomicInteger(0);
  4142. private Object respondToMethod;
  4143. private Object objectToYamlMethod;
  4144. private Map<String, DateTimeZone> localTimeZoneCache = new HashMap<String,DateTimeZone>();
  4145. /**
  4146. * A list of "external" finalizers (the ones, registered via ObjectSpace),
  4147. * weakly referenced, to be executed on tearDown.
  4148. */
  4149. private Map<Finalizable, Object> finalizers;
  4150. /**
  4151. * A list of JRuby-internal finalizers, weakly referenced,
  4152. * to be executed on tearDown.
  4153. */
  4154. private Map<Finalizable, Object> internalFinalizers;
  4155. // mutex that controls modifications of user-defined finalizers
  4156. private final Object finalizersMutex = new Object();
  4157. // mutex that controls modifications of internal finalizers
  4158. private final Object internalFinalizersMutex = new Object();
  4159. // A thread pool to use for executing this runtime's Ruby threads
  4160. private ExecutorService executor;
  4161. }
  4162. /***** BEGIN LICENSE BLOCK *****
  4163. * Version: CPL 1.0/GPL 2.0/LGPL 2.1
  4164. *
  4165. * The contents of this file are subject to the Common Public
  4166. * License Version 1.0 (the "License"); you may not use this file
  4167. * except in compliance with the License. You may obtain a copy of
  4168. * the License at http://www.eclipse.org/legal/cpl-v10.html
  4169. *
  4170. * Software distributed under the License is distributed on an "AS
  4171. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  4172. * implied. See the License for the specific language governing
  4173. * rights and limitations under the License.
  4174. *
  4175. * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
  4176. * Copyright (C) 2002-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
  4177. * Copyright (C) 2004 Thomas E Enebo <enebo@acm.org>
  4178. * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
  4179. * Copyright (C) 2007 Ola Bini <ola@ologix.com>
  4180. *
  4181. * Alternatively, the contents of this file may be used under the terms of
  4182. * either of the GNU General Public License Version 2 or later (the "GPL"),
  4183. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  4184. * in which case the provisions of the GPL or the LGPL are applicable instead
  4185. * of those above. If you wish to allow use of your version of this file only
  4186. * under the terms of either the GPL or the LGPL, and not to allow others to
  4187. * use your version of this file under the terms of the CPL, indicate your
  4188. * decision by deleting the provisions above and replace them with the notice
  4189. * and other provisions required by the GPL or the LGPL. If you do not delete
  4190. * the provisions above, a recipient may use your version of this file under
  4191. * the terms of any one of the CPL, the GPL or the LGPL.
  4192. ***** END LICENSE BLOCK *****/
  4193. package org.jruby;
  4194. import org.jruby.anno.FrameField;
  4195. import org.jruby.anno.JRubyMethod;
  4196. import org.jruby.runtime.Block;
  4197. import org.jruby.runtime.ThreadContext;
  4198. import org.jruby.runtime.builtin.IRubyObject;
  4199. import org.jruby.util.ByteList;
  4200. public class RubyArgsFile {
  4201. private static final class ArgsFileData {
  4202. private final Ruby runtime;
  4203. public ArgsFileData(Ruby runtime) {
  4204. this.runtime = runtime;
  4205. }
  4206. public IRubyObject currentFile;
  4207. public int currentLineNumber;
  4208. public boolean startedProcessing = false;
  4209. public boolean finishedProcessing = false;
  4210. public boolean nextArgsFile(ThreadContext context) {
  4211. if (finishedProcessing) {
  4212. return false;
  4213. }
  4214. RubyArray args = (RubyArray)runtime.getGlobalVariables().get("$*");
  4215. if (args.getLength() == 0) {
  4216. if (!startedProcessing) {
  4217. currentFile = runtime.getGlobalVariables().get("$stdin");
  4218. ((RubyString) runtime.getGlobalVariables().get("$FILENAME")).setValue(new ByteList(new byte[]{'-'}));
  4219. currentLineNumber = 0;
  4220. startedProcessing = true;
  4221. return true;
  4222. } else {
  4223. finishedProcessing = true;
  4224. return false;
  4225. }
  4226. }
  4227. IRubyObject arg = args.shift();
  4228. RubyString filename = (RubyString)((RubyObject)arg).to_s();
  4229. ByteList filenameBytes = filename.getByteList();
  4230. ((RubyString) runtime.getGlobalVariables().get("$FILENAME")).setValue(filenameBytes);
  4231. if (filenameBytes.length() == 1 && filenameBytes.get(0) == '-') {
  4232. currentFile = runtime.getGlobalVariables().get("$stdin");
  4233. } else {
  4234. currentFile = RubyFile.open(context, runtime.getFile(),
  4235. new IRubyObject[] {filename.strDup(context.getRuntime())}, Block.NULL_BLOCK);
  4236. }
  4237. startedProcessing = true;
  4238. return true;
  4239. }
  4240. public static ArgsFileData getDataFrom(IRubyObject recv) {
  4241. ArgsFileData data = (ArgsFileData)recv.dataGetStruct();
  4242. if(data == null) {
  4243. data = new ArgsFileData(recv.getRuntime());
  4244. recv.dataWrapStruct(data);
  4245. }
  4246. return data;
  4247. }
  4248. }
  4249. public static void setCurrentLineNumber(IRubyObject recv, int newLineNumber) {
  4250. ArgsFileData.getDataFrom(recv).currentLineNumber = newLineNumber;
  4251. }
  4252. public static void initArgsFile(Ruby runtime) {
  4253. RubyObject argsFile = new RubyObject(runtime, runtime.getObject());
  4254. runtime.getEnumerable().extend_object(argsFile);
  4255. runtime.defineReadonlyVariable("$<", argsFile);
  4256. runtime.defineGlobalConstant("ARGF", argsFile);
  4257. RubyClass argfClass = argsFile.getMetaClass();
  4258. argfClass.defineAnnotatedMethods(RubyArgsFile.class);
  4259. runtime.defineReadonlyVariable("$FILENAME", runtime.newString("-"));
  4260. }
  4261. @JRubyMethod(name = {"fileno", "to_i"})
  4262. public static IRubyObject fileno(ThreadContext context, IRubyObject recv) {
  4263. ArgsFileData data = ArgsFileData.getDataFrom(recv);
  4264. if (data.currentFile == null && !data.nextArgsFile(context)) {
  4265. throw context.getRuntime().newArgumentError("no stream");
  4266. }
  4267. return ((RubyIO) data.currentFile).fileno(context);
  4268. }
  4269. @JRubyMethod(name = "to_io")
  4270. public static IRubyObject to_io(ThreadContext context, IRubyObject recv) {
  4271. ArgsFileData data = ArgsFileData.getDataFrom(recv);
  4272. if (data.currentFile == null && !data.nextArgsFile(context)) {
  4273. throw context.getRuntime().newArgumentError("no stream");
  4274. }
  4275. return data.currentFile;
  4276. }
  4277. public static IRubyObject internalGets(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
  4278. ArgsFileData data = ArgsFileData.getDataFrom(recv);
  4279. if(data.currentFile == null && !data.nextArgsFile(context)) {
  4280. return context.getRuntime().getNil();
  4281. }
  4282. IRubyObject line = data.currentFile.callMethod(context, "gets", args);
  4283. while (line instanceof RubyNil) {
  4284. data.currentFile.callMethod(context, "close");
  4285. if (!data.nextArgsFile(context)) {
  4286. data.currentFile = null;
  4287. return line;
  4288. }
  4289. line = data.currentFile.callMethod(context, "gets", args);
  4290. }
  4291. data.currentLineNumber++;
  4292. context.getRuntime().getGlobalVariables().set("$.", context.getRuntime().newFixnum(data.currentLineNumber));
  4293. return line;
  4294. }
  4295. // ARGF methods
  4296. /** Read a line.
  4297. *
  4298. */
  4299. @JRubyMethod(name = "gets", optional = 1, frame = true, writes = FrameField.LASTLINE)
  4300. public static IRubyObject gets(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
  4301. IRubyObject result = internalGets(context, recv, args);
  4302. if (!result.isNil()) {
  4303. context.getCurrentFrame().setLastLine(result);
  4304. }
  4305. return result;
  4306. }
  4307. /** Read a line.
  4308. *
  4309. */
  4310. @JRubyMethod(name = "readline", optional = 1, frame = true, writes = FrameField.LASTLINE)
  4311. public static IRubyObject readline(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
  4312. IRubyObject line = gets(context, recv, args);
  4313. if (line.isNil()) {
  4314. throw context.getRuntime().newEOFError();
  4315. }
  4316. return line;
  4317. }
  4318. @JRubyMethod(name = "readlines", optional = 1, frame = true)
  4319. public static RubyArray readlines(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
  4320. IRubyObject[] separatorArgument;
  4321. if (args.length > 0) {
  4322. if (!context.getRuntime().getNilClass().isInstance(args[0]) &&
  4323. !context.getRuntime().getString().isInstance(args[0])) {
  4324. throw context.getRuntime().newTypeError(args[0], context.getRuntime().getString());
  4325. }
  4326. separatorArgument = new IRubyObject[] { args[0] };
  4327. } else {
  4328. separatorArgument = IRubyObject.NULL_ARRAY;
  4329. }
  4330. RubyArray result = context.getRuntime().newArray();
  4331. IRubyObject line;
  4332. while (! (line = internalGets(context, recv, separatorArgument)).isNil()) {
  4333. result.append(line);
  4334. }
  4335. return result;
  4336. }
  4337. @JRubyMethod(name = "each_byte", frame = true)
  4338. public static IRubyObject each_byte(ThreadContext context, IRubyObject recv, Block block) {
  4339. IRubyObject bt;
  4340. while(!(bt = getc(context, recv)).isNil()) {
  4341. block.yield(context, bt);
  4342. }
  4343. return recv;
  4344. }
  4345. /** Invoke a block for each line.
  4346. *
  4347. */
  4348. @JRubyMethod(name = "each_line", alias = {"each"}, optional = 1, frame = true)
  4349. public static IRubyObject each_line(ThreadContext context, IRubyObject recv, IRubyObject[] args, Block block) {
  4350. IRubyObject nextLine = internalGets(context, recv, args);
  4351. while (!nextLine.isNil()) {
  4352. block.yield(context, nextLine);
  4353. nextLine = internalGets(context, recv, args);
  4354. }
  4355. return recv;
  4356. }
  4357. @JRubyMethod(name = "file")
  4358. public static IRubyObject file(ThreadContext context, IRubyObject recv) {
  4359. ArgsFileData data = ArgsFileData.getDataFrom(recv);
  4360. if(data.currentFile == null && !data.nextArgsFile(context)) {
  4361. return context.getRuntime().getNil();
  4362. }
  4363. return data.currentFile;
  4364. }
  4365. @JRubyMethod(name = "skip")
  4366. public static IRubyObject skip(IRubyObject recv) {
  4367. ArgsFileData data = ArgsFileData.getDataFrom(recv);
  4368. data.currentFile = null;
  4369. return recv;
  4370. }
  4371. @JRubyMethod(name = "close")
  4372. public static IRubyObject close(ThreadContext context, IRubyObject recv) {
  4373. ArgsFileData data = ArgsFileData.getDataFrom(recv);
  4374. if(data.currentFile == null && !data.nextArgsFile(context)) {
  4375. return recv;
  4376. }
  4377. data.currentFile = null;
  4378. data.currentLineNumber = 0;
  4379. return recv;
  4380. }
  4381. @JRubyMethod(name = "closed?")
  4382. public static IRubyObject closed_p(ThreadContext context, IRubyObject recv) {
  4383. ArgsFileData data = ArgsFileData.getDataFrom(recv);
  4384. if(data.currentFile == null && !data.nextArgsFile(context)) {
  4385. return recv;
  4386. }
  4387. return ((RubyIO)data.currentFile).closed_p(context);
  4388. }
  4389. @JRubyMethod(name = "binmode")
  4390. public static IRubyObject binmode(ThreadContext context, IRubyObject recv) {
  4391. ArgsFileData data = ArgsFileData.getDataFrom(recv);
  4392. if(data.currentFile == null && !data.nextArgsFile(context)) {
  4393. throw context.getRuntime().newArgumentError("no stream");
  4394. }
  4395. return ((RubyIO)data.currentFile).binmode();
  4396. }
  4397. @JRubyMethod(name = "lineno")
  4398. public static IRubyObject lineno(ThreadContext context, IRubyObject recv) {
  4399. return context.getRuntime().newFixnum(ArgsFileData.getDataFrom(recv).currentLineNumber);
  4400. }
  4401. @JRubyMethod(name = "tell", alias = {"pos"})
  4402. public static IRubyObject tell(ThreadContext context, IRubyObject recv) {
  4403. ArgsFileData data = ArgsFileData.getDataFrom(recv);
  4404. if(data.currentFile == null && !data.nextArgsFile(context)) {
  4405. throw context.getRuntime().newArgumentError("no stream to tell");
  4406. }
  4407. return ((RubyIO)data.currentFile).pos(context);
  4408. }
  4409. @JRubyMethod(name = "rewind")
  4410. public static IRubyObject rewind(ThreadContext context, IRubyObject recv) {
  4411. ArgsFileData data = ArgsFileData.getDataFrom(recv);
  4412. if(data.currentFile == null && !data.nextArgsFile(context)) {
  4413. throw context.getRuntime().newArgumentError("no stream to rewind");
  4414. }
  4415. return ((RubyIO)data.currentFile).rewind(context);
  4416. }
  4417. @JRubyMethod(name = {"eof", "eof?"})
  4418. public static IRubyObject eof(ThreadContext context, IRubyObject recv) {
  4419. ArgsFileData data = ArgsFileData.getDataFrom(recv);
  4420. if (data.currentFile == null && !data.nextArgsFile(context)) {
  4421. return context.getRuntime().getTrue();
  4422. }
  4423. return ((RubyIO) data.currentFile).eof_p(context);
  4424. }
  4425. @JRubyMethod(name = "pos=", required = 1)
  4426. public static IRubyObject set_pos(ThreadContext context, IRubyObject recv, IRubyObject offset) {
  4427. ArgsFileData data = ArgsFileData.getDataFrom(recv);
  4428. if(data.currentFile == null && !data.nextArgsFile(context)) {
  4429. throw context.getRuntime().newArgumentError("no stream to set position");
  4430. }
  4431. return ((RubyIO)data.currentFile).pos_set(context, offset);
  4432. }
  4433. @JRubyMethod(name = "seek", required = 1, optional = 1)
  4434. public static IRubyObject seek(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
  4435. ArgsFileData data = ArgsFileData.getDataFrom(recv);
  4436. if(data.currentFile == null && !data.nextArgsFile(context)) {
  4437. throw context.getRuntime().newArgumentError("no stream to seek");
  4438. }
  4439. return ((RubyIO)data.currentFile).seek(context, args);
  4440. }
  4441. @JRubyMethod(name = "lineno=", required = 1)
  4442. public static IRubyObject set_lineno(ThreadContext context, IRubyObject recv, IRubyObject line) {
  4443. ArgsFileData data = ArgsFileData.getDataFrom(recv);
  4444. data.currentLineNumber = RubyNumeric.fix2int(line);
  4445. return context.getRuntime().getNil();
  4446. }
  4447. @JRubyMethod(name = "readchar")
  4448. public static IRubyObject readchar(ThreadContext context, IRubyObject recv) {
  4449. IRubyObject c = getc(context, recv);
  4450. if(c.isNil()) throw context.getRuntime().newEOFError();
  4451. return c;
  4452. }
  4453. @JRubyMethod(name = "getc")
  4454. public static IRubyObject getc(ThreadContext context, IRubyObject recv) {
  4455. ArgsFileData data = ArgsFileData.getDataFrom(recv);
  4456. IRubyObject bt;
  4457. while(true) {
  4458. if(data.currentFile == null && !data.nextArgsFile(context)) {
  4459. return context.getRuntime().getNil();
  4460. }
  4461. if(!(data.currentFile instanceof RubyFile)) {
  4462. bt = data.currentFile.callMethod(context,"getc");
  4463. } else {
  4464. bt = ((RubyIO)data.currentFile).getc();
  4465. }
  4466. if(bt.isNil()) {
  4467. data.currentFile = null;
  4468. continue;
  4469. }
  4470. return bt;
  4471. }
  4472. }
  4473. @JRubyMethod(name = "read", optional = 2)
  4474. public static IRubyObject read(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
  4475. Ruby runtime = context.getRuntime();
  4476. ArgsFileData data = ArgsFileData.getDataFrom(recv);
  4477. IRubyObject tmp, str, length;
  4478. long len = 0;
  4479. if(args.length > 0) {
  4480. length = args[0];
  4481. if(args.length > 1) {
  4482. str = args[1];
  4483. } else {
  4484. str = runtime.getNil();
  4485. }
  4486. } else {
  4487. length = str = runtime.getNil();
  4488. }
  4489. if(!length.isNil()) {
  4490. len = RubyNumeric.num2long(length);
  4491. }
  4492. if(!str.isNil()) {
  4493. str = str.convertToString();
  4494. ((RubyString)str).modify();
  4495. ((RubyString)str).getByteList().length(0);
  4496. args[1] = runtime.getNil();
  4497. }
  4498. while(true) {
  4499. if(data.currentFile == null && !data.nextArgsFile(context)) {
  4500. return str;
  4501. }
  4502. if(!(data.currentFile instanceof RubyIO)) {
  4503. tmp = data.currentFile.callMethod(context, "read", args);
  4504. } else {
  4505. tmp = ((RubyIO)data.currentFile).read(args);
  4506. }
  4507. if(str.isNil()) {
  4508. str = tmp;
  4509. } else if(!tmp.isNil()) {
  4510. ((RubyString)str).append(tmp);
  4511. }
  4512. if(tmp.isNil() || length.isNil()) {
  4513. data.currentFile = null;
  4514. continue;
  4515. } else if(args.length >= 1) {
  4516. if(((RubyString)str).getByteList().length() < len) {
  4517. len -= ((RubyString)str).getByteList().length();
  4518. args[0] = runtime.newFixnum(len);
  4519. continue;
  4520. }
  4521. }
  4522. return str;
  4523. }
  4524. }
  4525. @JRubyMethod(name = "filename", alias = {"path"})
  4526. public static RubyString filename(ThreadContext context, IRubyObject recv) {
  4527. return (RubyString) context.getRuntime().getGlobalVariables().get("$FILENAME");
  4528. }
  4529. @JRubyMethod(name = "to_s")
  4530. public static IRubyObject to_s(IRubyObject recv) {
  4531. return recv.getRuntime().newString("ARGF");
  4532. }
  4533. }
  4534. /*
  4535. **** BEGIN LICENSE BLOCK *****
  4536. * Version: CPL 1.0/GPL 2.0/LGPL 2.1
  4537. *
  4538. * The contents of this file are subject to the Common Public
  4539. * License Version 1.0 (the "License"); you may not use this file
  4540. * except in compliance with the License. You may obtain a copy of
  4541. * the License at http://www.eclipse.org/legal/cpl-v10.html
  4542. *
  4543. * Software distributed under the License is distributed on an "AS
  4544. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  4545. * implied. See the License for the specific language governing
  4546. * rights and limitations under the License.
  4547. *
  4548. * Copyright (C) 2001 Alan Moore <alan_moore@gmx.net>
  4549. * Copyright (C) 2001 Chad Fowler <chadfowler@chadfowler.com>
  4550. * Copyright (C) 2001-2002 Benoit Cerrina <b.cerrina@wanadoo.fr>
  4551. * Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
  4552. * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
  4553. * Copyright (C) 2002-2005 Thomas E Enebo <enebo@acm.org>
  4554. * Copyright (C) 2004-2005 Charles O Nutter <headius@headius.com>
  4555. * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
  4556. * Copyright (C) 2006 Ola Bini <Ola.Bini@ki.se>
  4557. * Copyright (C) 2006 Daniel Steer <damian.steer@hp.com>
  4558. *
  4559. * Alternatively, the contents of this file may be used under the terms of
  4560. * either of the GNU General Public License Version 2 or later (the "GPL"),
  4561. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  4562. * in which case the provisions of the GPL or the LGPL are applicable instead
  4563. * of those above. If you wish to allow use of your version of this file only
  4564. * under the terms of either the GPL or the LGPL, and not to allow others to
  4565. * use your version of this file under the terms of the CPL, indicate your
  4566. * decision by deleting the provisions above and replace them with the notice
  4567. * and other provisions required by the GPL or the LGPL. If you do not delete
  4568. * the provisions above, a recipient may use your version of this file under
  4569. * the terms of any one of the CPL, the GPL or the LGPL.
  4570. ***** END LICENSE BLOCK *****/
  4571. package org.jruby;
  4572. import java.lang.reflect.Array;
  4573. import java.io.IOException;
  4574. import java.util.Arrays;
  4575. import java.util.Collection;
  4576. import java.util.Comparator;
  4577. import java.util.Iterator;
  4578. import java.util.List;
  4579. import java.util.ListIterator;
  4580. import org.jruby.anno.JRubyMethod;
  4581. import org.jruby.anno.JRubyClass;
  4582. import org.jruby.common.IRubyWarnings.ID;
  4583. import org.jruby.javasupport.JavaUtil;
  4584. import org.jruby.runtime.Arity;
  4585. import org.jruby.runtime.Block;
  4586. import org.jruby.runtime.ClassIndex;
  4587. import org.jruby.runtime.MethodIndex;
  4588. import org.jruby.runtime.ObjectAllocator;
  4589. import org.jruby.runtime.ThreadContext;
  4590. import org.jruby.runtime.Visibility;
  4591. import org.jruby.runtime.builtin.IRubyObject;
  4592. import org.jruby.runtime.marshal.MarshalStream;
  4593. import org.jruby.runtime.marshal.UnmarshalStream;
  4594. import org.jruby.util.ByteList;
  4595. import org.jruby.util.Pack;
  4596. /**
  4597. * The implementation of the built-in class Array in Ruby.
  4598. *
  4599. * Concurrency: no synchronization is required among readers, but
  4600. * all users must synchronize externally with writers.
  4601. *
  4602. */
  4603. @JRubyClass(name="Array")
  4604. public class RubyArray extends RubyObject implements List {
  4605. public static RubyClass createArrayClass(Ruby runtime) {
  4606. RubyClass arrayc = runtime.defineClass("Array", runtime.getObject(), ARRAY_ALLOCATOR);
  4607. runtime.setArray(arrayc);
  4608. arrayc.index = ClassIndex.ARRAY;
  4609. arrayc.kindOf = new RubyModule.KindOf() {
  4610. @Override
  4611. public boolean isKindOf(IRubyObject obj, RubyModule type) {
  4612. return obj instanceof RubyArray;
  4613. }
  4614. };
  4615. arrayc.includeModule(runtime.getEnumerable());
  4616. arrayc.defineAnnotatedMethods(RubyArray.class);
  4617. return arrayc;
  4618. }
  4619. private static ObjectAllocator ARRAY_ALLOCATOR = new ObjectAllocator() {
  4620. public IRubyObject allocate(Ruby runtime, RubyClass klass) {
  4621. return new RubyArray(runtime, klass);
  4622. }
  4623. };
  4624. @Override
  4625. public int getNativeTypeIndex() {
  4626. return ClassIndex.ARRAY;
  4627. }
  4628. private final void concurrentModification() {
  4629. throw getRuntime().newConcurrencyError("Detected invalid array contents due to unsynchronized modifications with concurrent users");
  4630. }
  4631. /** rb_ary_s_create
  4632. *
  4633. */
  4634. @JRubyMethod(name = "[]", rest = true, frame = true, meta = true)
  4635. public static IRubyObject create(IRubyObject klass, IRubyObject[] args, Block block) {
  4636. RubyArray arr = (RubyArray) ((RubyClass) klass).allocate();
  4637. arr.callInit(IRubyObject.NULL_ARRAY, block);
  4638. if (args.length > 0) {
  4639. arr.alloc(args.length);
  4640. System.arraycopy(args, 0, arr.values, 0, args.length);
  4641. arr.realLength = args.length;
  4642. }
  4643. return arr;
  4644. }
  4645. /** rb_ary_new2
  4646. *
  4647. */
  4648. public static final RubyArray newArray(final Ruby runtime, final long len) {
  4649. return new RubyArray(runtime, len);
  4650. }
  4651. public static final RubyArray newArrayLight(final Ruby runtime, final long len) {
  4652. return new RubyArray(runtime, len, false);
  4653. }
  4654. /** rb_ary_new
  4655. *
  4656. */
  4657. public static final RubyArray newArray(final Ruby runtime) {
  4658. return new RubyArray(runtime, ARRAY_DEFAULT_SIZE);
  4659. }
  4660. /** rb_ary_new
  4661. *
  4662. */
  4663. public static final RubyArray newArrayLight(final Ruby runtime) {
  4664. /* Ruby arrays default to holding 16 elements, so we create an
  4665. * ArrayList of the same size if we're not told otherwise
  4666. */
  4667. RubyArray arr = new RubyArray(runtime, false);
  4668. arr.alloc(ARRAY_DEFAULT_SIZE);
  4669. return arr;
  4670. }
  4671. public static RubyArray newArray(Ruby runtime, IRubyObject obj) {
  4672. return new RubyArray(runtime, new IRubyObject[] { obj });
  4673. }
  4674. public static RubyArray newArrayLight(Ruby runtime, IRubyObject obj) {
  4675. return new RubyArray(runtime, new IRubyObject[] { obj }, false);
  4676. }
  4677. /** rb_assoc_new
  4678. *
  4679. */
  4680. public static RubyArray newArray(Ruby runtime, IRubyObject car, IRubyObject cdr) {
  4681. return new RubyArray(runtime, new IRubyObject[] { car, cdr });
  4682. }
  4683. public static RubyArray newEmptyArray(Ruby runtime) {
  4684. return new RubyArray(runtime, NULL_ARRAY);
  4685. }
  4686. /** rb_ary_new4, rb_ary_new3
  4687. *
  4688. */
  4689. public static RubyArray newArray(Ruby runtime, IRubyObject[] args) {
  4690. RubyArray arr = new RubyArray(runtime, args.length);
  4691. System.arraycopy(args, 0, arr.values, 0, args.length);
  4692. arr.realLength = args.length;
  4693. return arr;
  4694. }
  4695. public static RubyArray newArrayNoCopy(Ruby runtime, IRubyObject[] args) {
  4696. return new RubyArray(runtime, args);
  4697. }
  4698. public static RubyArray newArrayNoCopy(Ruby runtime, IRubyObject[] args, int begin) {
  4699. return new RubyArray(runtime, args, begin);
  4700. }
  4701. public static RubyArray newArrayNoCopyLight(Ruby runtime, IRubyObject[] args) {
  4702. RubyArray arr = new RubyArray(runtime, false);
  4703. arr.values = args;
  4704. arr.realLength = args.length;
  4705. return arr;
  4706. }
  4707. public static RubyArray newArray(Ruby runtime, Collection collection) {
  4708. RubyArray arr = new RubyArray(runtime, collection.size());
  4709. collection.toArray(arr.values);
  4710. arr.realLength = arr.values.length;
  4711. return arr;
  4712. }
  4713. public static final int ARRAY_DEFAULT_SIZE = 16;
  4714. // volatile to ensure that initial nil-fill is visible to other threads
  4715. private volatile IRubyObject[] values;
  4716. private static final int TMPLOCK_ARR_F = 1 << 9;
  4717. private static final int TMPLOCK_OR_FROZEN_ARR_F = TMPLOCK_ARR_F | FROZEN_F;
  4718. private volatile boolean isShared = false;
  4719. private int begin = 0;
  4720. private int realLength = 0;
  4721. /*
  4722. * plain internal array assignment
  4723. */
  4724. private RubyArray(Ruby runtime, IRubyObject[] vals) {
  4725. super(runtime, runtime.getArray());
  4726. values = vals;
  4727. realLength = vals.length;
  4728. }
  4729. /*
  4730. * plain internal array assignment
  4731. */
  4732. private RubyArray(Ruby runtime, IRubyObject[] vals, boolean objectSpace) {
  4733. super(runtime, runtime.getArray(), objectSpace);
  4734. values = vals;
  4735. realLength = vals.length;
  4736. }
  4737. /*
  4738. * plain internal array assignment
  4739. */
  4740. private RubyArray(Ruby runtime, IRubyObject[] vals, int begin) {
  4741. super(runtime, runtime.getArray());
  4742. this.values = vals;
  4743. this.begin = begin;
  4744. this.realLength = vals.length - begin;
  4745. this.isShared = true;
  4746. }
  4747. /* rb_ary_new2
  4748. * just allocates the internal array
  4749. */
  4750. private RubyArray(Ruby runtime, long length) {
  4751. super(runtime, runtime.getArray());
  4752. checkLength(length);
  4753. alloc((int) length);
  4754. }
  4755. private RubyArray(Ruby runtime, long length, boolean objectspace) {
  4756. super(runtime, runtime.getArray(), objectspace);
  4757. checkLength(length);
  4758. alloc((int)length);
  4759. }
  4760. /* rb_ary_new3, rb_ary_new4
  4761. * allocates the internal array of size length and copies the 'length' elements
  4762. */
  4763. public RubyArray(Ruby runtime, long length, IRubyObject[] vals) {
  4764. super(runtime, runtime.getArray());
  4765. checkLength(length);
  4766. int ilength = (int) length;
  4767. alloc(ilength);
  4768. if (ilength > 0 && vals.length > 0) System.arraycopy(vals, 0, values, 0, ilength);
  4769. realLength = ilength;
  4770. }
  4771. /* NEWOBJ and OBJSETUP equivalent
  4772. * fastest one, for shared arrays, optional objectspace
  4773. */
  4774. private RubyArray(Ruby runtime, boolean objectSpace) {
  4775. super(runtime, runtime.getArray(), objectSpace);
  4776. }
  4777. private RubyArray(Ruby runtime) {
  4778. super(runtime, runtime.getArray());
  4779. alloc(ARRAY_DEFAULT_SIZE);
  4780. }
  4781. public RubyArray(Ruby runtime, RubyClass klass) {
  4782. super(runtime, klass);
  4783. alloc(ARRAY_DEFAULT_SIZE);
  4784. }
  4785. /* Array constructors taking the MetaClass to fulfil MRI Array subclass behaviour
  4786. *
  4787. */
  4788. private RubyArray(Ruby runtime, RubyClass klass, int length) {
  4789. super(runtime, klass);
  4790. alloc(length);
  4791. }
  4792. private RubyArray(Ruby runtime, RubyClass klass, long length) {
  4793. super(runtime, klass);
  4794. checkLength(length);
  4795. alloc((int)length);
  4796. }
  4797. private RubyArray(Ruby runtime, RubyClass klass, long length, boolean objectspace) {
  4798. super(runtime, klass, objectspace);
  4799. checkLength(length);
  4800. alloc((int)length);
  4801. }
  4802. private RubyArray(Ruby runtime, RubyClass klass, boolean objectSpace) {
  4803. super(runtime, klass, objectSpace);
  4804. }
  4805. private RubyArray(Ruby runtime, RubyClass klass, RubyArray original) {
  4806. super(runtime, klass);
  4807. realLength = original.realLength;
  4808. alloc(realLength);
  4809. try {
  4810. System.arraycopy(original.values, original.begin, values, 0, realLength);
  4811. } catch (ArrayIndexOutOfBoundsException e) {
  4812. concurrentModification();
  4813. }
  4814. }
  4815. private final IRubyObject[] reserve(int length) {
  4816. final IRubyObject[] arr = new IRubyObject[length];
  4817. Arrays.fill(arr, getRuntime().getNil());
  4818. return arr;
  4819. }
  4820. private final void alloc(int length) {
  4821. final IRubyObject[] newValues = new IRubyObject[length];
  4822. Arrays.fill(newValues, getRuntime().getNil());
  4823. values = newValues;
  4824. }
  4825. private final void realloc(int newLength) {
  4826. IRubyObject[] reallocated = new IRubyObject[newLength];
  4827. Arrays.fill(reallocated, getRuntime().getNil());
  4828. try {
  4829. System.arraycopy(values, 0, reallocated, 0, newLength > realLength ? realLength : newLength);
  4830. } catch (ArrayIndexOutOfBoundsException e) {
  4831. concurrentModification();
  4832. }
  4833. values = reallocated;
  4834. }
  4835. private final void checkLength(long length) {
  4836. if (length < 0) {
  4837. throw getRuntime().newArgumentError("negative array size (or size too big)");
  4838. }
  4839. if (length >= Integer.MAX_VALUE) {
  4840. throw getRuntime().newArgumentError("array size too big");
  4841. }
  4842. }
  4843. /** Getter for property list.
  4844. * @return Value of property list.
  4845. */
  4846. public List getList() {
  4847. return Arrays.asList(toJavaArray());
  4848. }
  4849. public int getLength() {
  4850. return realLength;
  4851. }
  4852. public IRubyObject[] toJavaArray() {
  4853. IRubyObject[] copy = reserve(realLength);
  4854. try {
  4855. System.arraycopy(values, begin, copy, 0, realLength);
  4856. } catch (ArrayIndexOutOfBoundsException e) {
  4857. concurrentModification();
  4858. }
  4859. return copy;
  4860. }
  4861. public IRubyObject[] toJavaArrayUnsafe() {
  4862. return !isShared ? values : toJavaArray();
  4863. }
  4864. public IRubyObject[] toJavaArrayMaybeUnsafe() {
  4865. return (!isShared && begin == 0 && values.length == realLength) ? values : toJavaArray();
  4866. }
  4867. /** rb_ary_make_shared
  4868. *
  4869. */
  4870. private final RubyArray makeShared(int beg, int len, RubyClass klass) {
  4871. return makeShared(beg, len, klass, klass.getRuntime().isObjectSpaceEnabled());
  4872. }
  4873. /** rb_ary_make_shared
  4874. *
  4875. */
  4876. private final RubyArray makeShared(int beg, int len, RubyClass klass, boolean objectSpace) {
  4877. RubyArray sharedArray = new RubyArray(getRuntime(), klass, objectSpace);
  4878. isShared = true;
  4879. sharedArray.values = values;
  4880. sharedArray.isShared = true;
  4881. sharedArray.begin = beg;
  4882. sharedArray.realLength = len;
  4883. return sharedArray;
  4884. }
  4885. /** rb_ary_modify_check
  4886. *
  4887. */
  4888. private final void modifyCheck() {
  4889. if ((flags & TMPLOCK_OR_FROZEN_ARR_F) != 0) {
  4890. if ((flags & FROZEN_F) != 0) throw getRuntime().newFrozenError("array");
  4891. if ((flags & TMPLOCK_ARR_F) != 0) throw getRuntime().newTypeError("can't modify array during iteration");
  4892. }
  4893. if (!isTaint() && getRuntime().getSafeLevel() >= 4) {
  4894. throw getRuntime().newSecurityError("Insecure: can't modify array");
  4895. }
  4896. }
  4897. /** rb_ary_modify
  4898. *
  4899. */
  4900. private final void modify() {
  4901. modifyCheck();
  4902. if (isShared) {
  4903. IRubyObject[] vals = reserve(realLength);
  4904. isShared = false;
  4905. try {
  4906. System.arraycopy(values, begin, vals, 0, realLength);
  4907. } catch (ArrayIndexOutOfBoundsException e) {
  4908. concurrentModification();
  4909. }
  4910. begin = 0;
  4911. values = vals;
  4912. }
  4913. }
  4914. /* ================
  4915. * Instance Methods
  4916. * ================
  4917. */
  4918. /** rb_ary_initialize
  4919. *
  4920. */
  4921. @JRubyMethod(name = "initialize", required = 0, optional = 2, frame = true, visibility = Visibility.PRIVATE)
  4922. public IRubyObject initialize(ThreadContext context, IRubyObject[] args, Block block) {
  4923. int argc = args.length;
  4924. Ruby runtime = getRuntime();
  4925. if (argc == 0) {
  4926. modifyCheck();
  4927. realLength = 0;
  4928. if (block.isGiven()) runtime.getWarnings().warn(ID.BLOCK_UNUSED, "given block not used");
  4929. return this;
  4930. }
  4931. if (argc == 1 && !(args[0] instanceof RubyFixnum)) {
  4932. IRubyObject val = args[0].checkArrayType();
  4933. if (!val.isNil()) {
  4934. replace(val);
  4935. return this;
  4936. }
  4937. }
  4938. long len = RubyNumeric.num2long(args[0]);
  4939. if (len < 0) throw runtime.newArgumentError("negative array size");
  4940. if (len >= Integer.MAX_VALUE) throw runtime.newArgumentError("array size too big");
  4941. int ilen = (int) len;
  4942. modify();
  4943. if (ilen > values.length) values = reserve(ilen);
  4944. if (block.isGiven()) {
  4945. if (argc == 2) {
  4946. runtime.getWarnings().warn(ID.BLOCK_BEATS_DEFAULT_VALUE, "block supersedes default value argument");
  4947. }
  4948. for (int i = 0; i < ilen; i++) {
  4949. store(i, block.yield(context, new RubyFixnum(runtime, i)));
  4950. realLength = i + 1;
  4951. }
  4952. } else {
  4953. try {
  4954. Arrays.fill(values, 0, ilen, (argc == 2) ? args[1] : runtime.getNil());
  4955. } catch (ArrayIndexOutOfBoundsException e) {
  4956. concurrentModification();
  4957. }
  4958. realLength = ilen;
  4959. }
  4960. return this;
  4961. }
  4962. /** rb_ary_initialize_copy
  4963. *
  4964. */
  4965. @JRubyMethod(name = {"initialize_copy"}, required = 1, visibility=Visibility.PRIVATE)
  4966. @Override
  4967. public IRubyObject initialize_copy(IRubyObject orig) {
  4968. return this.replace(orig);
  4969. }
  4970. /** rb_ary_replace
  4971. *
  4972. */
  4973. @JRubyMethod(name = {"replace"}, required = 1)
  4974. public IRubyObject replace(IRubyObject orig) {
  4975. modifyCheck();
  4976. RubyArray origArr = orig.convertToArray();
  4977. if (this == orig) return this;
  4978. origArr.isShared = true;
  4979. isShared = true;
  4980. values = origArr.values;
  4981. realLength = origArr.realLength;
  4982. begin = origArr.begin;
  4983. return this;
  4984. }
  4985. /** rb_ary_to_s
  4986. *
  4987. */
  4988. @JRubyMethod(name = "to_s")
  4989. @Override
  4990. public IRubyObject to_s() {
  4991. if (realLength == 0) return RubyString.newEmptyString(getRuntime());
  4992. return join(getRuntime().getCurrentContext(), getRuntime().getGlobalVariables().get("$,"));
  4993. }
  4994. public boolean includes(ThreadContext context, IRubyObject item) {
  4995. int begin = this.begin;
  4996. for (int i = begin; i < begin + realLength; i++) {
  4997. final IRubyObject value;
  4998. try {
  4999. value = values[i];
  5000. } catch (ArrayIndexOutOfBoundsException e) {
  5001. concurrentModification();
  5002. continue;
  5003. }
  5004. if (equalInternal(context, value, item)) return true;
  5005. }
  5006. return false;
  5007. }
  5008. /** rb_ary_hash
  5009. *
  5010. */
  5011. @JRubyMethod(name = "hash")
  5012. public RubyFixnum hash(ThreadContext context) {
  5013. int h = realLength;
  5014. Ruby runtime = getRuntime();
  5015. int begin = this.begin;
  5016. for (int i = begin; i < begin + realLength; i++) {
  5017. h = (h << 1) | (h < 0 ? 1 : 0);
  5018. final IRubyObject value;
  5019. try {
  5020. value = values[i];
  5021. } catch (ArrayIndexOutOfBoundsException e) {
  5022. concurrentModification();
  5023. continue;
  5024. }
  5025. h ^= RubyNumeric.num2long(value.callMethod(context, MethodIndex.HASH, "hash"));
  5026. }
  5027. return runtime.newFixnum(h);
  5028. }
  5029. /** rb_ary_store
  5030. *
  5031. */
  5032. public final IRubyObject store(long index, IRubyObject value) {
  5033. if (index < 0) {
  5034. index += realLength;
  5035. if (index < 0) {
  5036. throw getRuntime().newIndexError("index " + (index - realLength) + " out of array");
  5037. }
  5038. }
  5039. modify();
  5040. if (index >= realLength) {
  5041. if (index >= values.length) {
  5042. long newLength = values.length >> 1;
  5043. if (newLength < ARRAY_DEFAULT_SIZE) newLength = ARRAY_DEFAULT_SIZE;
  5044. newLength += index;
  5045. if (index >= Integer.MAX_VALUE || newLength >= Integer.MAX_VALUE) {
  5046. throw getRuntime().newArgumentError("index too big");
  5047. }
  5048. realloc((int) newLength);
  5049. }
  5050. realLength = (int) index + 1;
  5051. }
  5052. try {
  5053. values[(int) index] = value;
  5054. } catch (ArrayIndexOutOfBoundsException e) {
  5055. concurrentModification();
  5056. }
  5057. return value;
  5058. }
  5059. /** rb_ary_elt
  5060. *
  5061. */
  5062. private final IRubyObject elt(long offset) {
  5063. if (offset < 0 || offset >= realLength) {
  5064. return getRuntime().getNil();
  5065. }
  5066. try {
  5067. return values[begin + (int)offset];
  5068. } catch (ArrayIndexOutOfBoundsException e) {
  5069. concurrentModification();
  5070. return getRuntime().getNil();
  5071. }
  5072. }
  5073. /** rb_ary_entry
  5074. *
  5075. */
  5076. public final IRubyObject entry(long offset) {
  5077. return (offset < 0 ) ? elt(offset + realLength) : elt(offset);
  5078. }
  5079. /** rb_ary_entry
  5080. *
  5081. */
  5082. public final IRubyObject entry(int offset) {
  5083. return (offset < 0 ) ? elt(offset + realLength) : elt(offset);
  5084. }
  5085. public final IRubyObject eltInternal(int offset) {
  5086. return values[begin + offset];
  5087. }
  5088. public final IRubyObject eltInternalSet(int offset, IRubyObject item) {
  5089. return values[begin + offset] = item;
  5090. }
  5091. /**
  5092. * Variable arity version for compatibility. Not bound to a Ruby method.
  5093. * @deprecated Use the versions with zero, one, or two args.
  5094. */
  5095. public IRubyObject fetch(ThreadContext context, IRubyObject[] args, Block block) {
  5096. switch (args.length) {
  5097. case 1:
  5098. return fetch(context, args[0], block);
  5099. case 2:
  5100. return fetch(context, args[0], args[1], block);
  5101. default:
  5102. Arity.raiseArgumentError(getRuntime(), args.length, 1, 2);
  5103. return null; // not reached
  5104. }
  5105. }
  5106. /** rb_ary_fetch
  5107. *
  5108. */
  5109. @JRubyMethod(name = "fetch", frame = true)
  5110. public IRubyObject fetch(ThreadContext context, IRubyObject arg0, Block block) {
  5111. long index = RubyNumeric.num2long(arg0);
  5112. if (index < 0) index += realLength;
  5113. if (index < 0 || index >= realLength) {
  5114. if (block.isGiven()) return block.yield(context, arg0);
  5115. throw getRuntime().newIndexError("index " + index + " out of array");
  5116. }
  5117. try {
  5118. return values[begin + (int) index];
  5119. } catch (ArrayIndexOutOfBoundsException e) {
  5120. concurrentModification();
  5121. return getRuntime().getNil();
  5122. }
  5123. }
  5124. /** rb_ary_fetch
  5125. *
  5126. */
  5127. @JRubyMethod(name = "fetch", frame = true)
  5128. public IRubyObject fetch(ThreadContext context, IRubyObject arg0, IRubyObject arg1, Block block) {
  5129. if (block.isGiven()) getRuntime().getWarnings().warn(ID.BLOCK_BEATS_DEFAULT_VALUE, "block supersedes default value argument");
  5130. long index = RubyNumeric.num2long(arg0);
  5131. if (index < 0) index += realLength;
  5132. if (index < 0 || index >= realLength) {
  5133. if (block.isGiven()) return block.yield(context, arg0);
  5134. return arg1;
  5135. }
  5136. try {
  5137. return values[begin + (int) index];
  5138. } catch (ArrayIndexOutOfBoundsException e) {
  5139. concurrentModification();
  5140. return getRuntime().getNil();
  5141. }
  5142. }
  5143. /** rb_ary_to_ary
  5144. *
  5145. */
  5146. private static RubyArray aryToAry(IRubyObject obj) {
  5147. if (obj instanceof RubyArray) return (RubyArray) obj;
  5148. if (obj.respondsTo("to_ary")) return obj.convertToArray();
  5149. RubyArray arr = new RubyArray(obj.getRuntime(), false); // possibly should not in object space
  5150. arr.alloc(1);
  5151. arr.values[0] = obj;
  5152. arr.realLength = 1;
  5153. return arr;
  5154. }
  5155. /** rb_ary_splice
  5156. *
  5157. */
  5158. private final void splice(long beg, long len, IRubyObject rpl) {
  5159. if (len < 0) throw getRuntime().newIndexError("negative length (" + len + ")");
  5160. if (beg < 0) {
  5161. beg += realLength;
  5162. if (beg < 0) {
  5163. beg -= realLength;
  5164. throw getRuntime().newIndexError("index " + beg + " out of array");
  5165. }
  5166. }
  5167. final RubyArray rplArr;
  5168. final int rlen;
  5169. if (rpl == null || rpl.isNil()) {
  5170. rplArr = null;
  5171. rlen = 0;
  5172. } else {
  5173. rplArr = aryToAry(rpl);
  5174. rlen = rplArr.realLength;
  5175. }
  5176. modify();
  5177. if (beg >= realLength) {
  5178. len = beg + rlen;
  5179. if (len >= values.length) {
  5180. int tryNewLength = values.length + (values.length >> 1);
  5181. realloc(len > tryNewLength ? (int)len : tryNewLength);
  5182. }
  5183. realLength = (int) len;
  5184. } else {
  5185. if (beg + len > realLength) len = realLength - beg;
  5186. long alen = realLength + rlen - len;
  5187. if (alen >= values.length) {
  5188. int tryNewLength = values.length + (values.length >> 1);
  5189. realloc(alen > tryNewLength ? (int)alen : tryNewLength);
  5190. }
  5191. if (len != rlen) {
  5192. try {
  5193. System.arraycopy(values, (int) (beg + len), values, (int) beg + rlen, realLength - (int) (beg + len));
  5194. } catch (ArrayIndexOutOfBoundsException e) {
  5195. concurrentModification();
  5196. }
  5197. realLength = (int) alen;
  5198. }
  5199. }
  5200. if (rlen > 0) {
  5201. try {
  5202. System.arraycopy(rplArr.values, rplArr.begin, values, (int) beg, rlen);
  5203. } catch (ArrayIndexOutOfBoundsException e) {
  5204. concurrentModification();
  5205. }
  5206. }
  5207. }
  5208. /** rb_ary_splice
  5209. *
  5210. */
  5211. private final void spliceOne(long beg, long len, IRubyObject rpl) {
  5212. if (len < 0) throw getRuntime().newIndexError("negative length (" + len + ")");
  5213. if (beg < 0) {
  5214. beg += realLength;
  5215. if (beg < 0) {
  5216. beg -= realLength;
  5217. throw getRuntime().newIndexError("index " + beg + " out of array");
  5218. }
  5219. }
  5220. modify();
  5221. if (beg >= realLength) {
  5222. len = beg + 1;
  5223. if (len >= values.length) {
  5224. int tryNewLength = values.length + (values.length >> 1);
  5225. realloc(len > tryNewLength ? (int)len : tryNewLength);
  5226. }
  5227. realLength = (int) len;
  5228. } else {
  5229. if (beg + len > realLength) len = realLength - beg;
  5230. int alen = realLength + 1 - (int)len;
  5231. if (alen >= values.length) {
  5232. int tryNewLength = values.length + (values.length >> 1);
  5233. realloc(alen > tryNewLength ? alen : tryNewLength);
  5234. }
  5235. if (len != 1) {
  5236. try {
  5237. System.arraycopy(values, (int) (beg + len), values, (int) beg + 1, realLength - (int) (beg + len));
  5238. } catch (ArrayIndexOutOfBoundsException e) {
  5239. concurrentModification();
  5240. }
  5241. realLength = alen;
  5242. }
  5243. }
  5244. try {
  5245. values[(int)beg] = rpl;
  5246. } catch (ArrayIndexOutOfBoundsException e) {
  5247. concurrentModification();
  5248. }
  5249. }
  5250. @JRubyMethod
  5251. public IRubyObject insert() {
  5252. throw getRuntime().newArgumentError(0, 1);
  5253. }
  5254. /** rb_ary_insert
  5255. *
  5256. */
  5257. @JRubyMethod
  5258. public IRubyObject insert(IRubyObject arg) {
  5259. return this;
  5260. }
  5261. /** rb_ary_insert
  5262. *
  5263. */
  5264. @JRubyMethod
  5265. public IRubyObject insert(IRubyObject arg1, IRubyObject arg2) {
  5266. long pos = RubyNumeric.num2long(arg1);
  5267. if (pos == -1) pos = realLength;
  5268. if (pos < 0) pos++;
  5269. spliceOne(pos, 0, arg2); // rb_ary_new4
  5270. return this;
  5271. }
  5272. /** rb_ary_insert
  5273. *
  5274. */
  5275. @JRubyMethod(name = "insert", required = 1, rest = true)
  5276. public IRubyObject insert(IRubyObject[] args) {
  5277. if (args.length == 1) return this;
  5278. long pos = RubyNumeric.num2long(args[0]);
  5279. if (pos == -1) pos = realLength;
  5280. if (pos < 0) pos++;
  5281. RubyArray inserted = new RubyArray(getRuntime(), false);
  5282. inserted.values = args;
  5283. inserted.begin = 1;
  5284. inserted.realLength = args.length - 1;
  5285. splice(pos, 0, inserted); // rb_ary_new4
  5286. return this;
  5287. }
  5288. /** rb_ary_dup
  5289. *
  5290. */
  5291. public final RubyArray aryDup() {
  5292. RubyArray dup = new RubyArray(getRuntime(), getMetaClass(), this);
  5293. dup.flags |= flags & TAINTED_F; // from DUP_SETUP
  5294. // rb_copy_generic_ivar from DUP_SETUP here ...unlikely..
  5295. return dup;
  5296. }
  5297. /** rb_ary_transpose
  5298. *
  5299. */
  5300. @JRubyMethod(name = "transpose")
  5301. public RubyArray transpose() {
  5302. RubyArray tmp, result = null;
  5303. int alen = realLength;
  5304. if (alen == 0) return aryDup();
  5305. Ruby runtime = getRuntime();
  5306. int elen = -1;
  5307. int end = begin + alen;
  5308. for (int i = begin; i < end; i++) {
  5309. tmp = elt(i).convertToArray();
  5310. if (elen < 0) {
  5311. elen = tmp.realLength;
  5312. result = new RubyArray(runtime, elen);
  5313. for (int j = 0; j < elen; j++) {
  5314. result.store(j, new RubyArray(runtime, alen));
  5315. }
  5316. } else if (elen != tmp.realLength) {
  5317. throw runtime.newIndexError("element size differs (" + tmp.realLength
  5318. + " should be " + elen + ")");
  5319. }
  5320. for (int j = 0; j < elen; j++) {
  5321. ((RubyArray) result.elt(j)).store(i - begin, tmp.elt(j));
  5322. }
  5323. }
  5324. return result;
  5325. }
  5326. /** rb_values_at (internal)
  5327. *
  5328. */
  5329. private final IRubyObject values_at(long olen, IRubyObject[] args) {
  5330. RubyArray result = new RubyArray(getRuntime(), args.length);
  5331. for (int i = 0; i < args.length; i++) {
  5332. if (args[i] instanceof RubyFixnum) {
  5333. result.append(entry(((RubyFixnum)args[i]).getLongValue()));
  5334. continue;
  5335. }
  5336. long beglen[];
  5337. if (!(args[i] instanceof RubyRange)) {
  5338. } else if ((beglen = ((RubyRange) args[i]).begLen(olen, 0)) == null) {
  5339. continue;
  5340. } else {
  5341. int beg = (int) beglen[0];
  5342. int len = (int) beglen[1];
  5343. int end = begin + len;
  5344. for (int j = begin; j < end; j++) {
  5345. result.append(entry(j + beg));
  5346. }
  5347. continue;
  5348. }
  5349. result.append(entry(RubyNumeric.num2long(args[i])));
  5350. }
  5351. return result;
  5352. }
  5353. /** rb_values_at
  5354. *
  5355. */
  5356. @JRubyMethod(name = "values_at", rest = true)
  5357. public IRubyObject values_at(IRubyObject[] args) {
  5358. return values_at(realLength, args);
  5359. }
  5360. /** rb_ary_subseq
  5361. *
  5362. */
  5363. public IRubyObject subseq(long beg, long len) {
  5364. if (beg > realLength || beg < 0 || len < 0) return getRuntime().getNil();
  5365. if (beg + len > realLength) {
  5366. len = realLength - beg;
  5367. if (len < 0) len = 0;
  5368. }
  5369. if (len == 0) return new RubyArray(getRuntime(), getMetaClass(), 0);
  5370. return makeShared(begin + (int) beg, (int) len, getMetaClass());
  5371. }
  5372. /** rb_ary_subseq
  5373. *
  5374. */
  5375. public IRubyObject subseqLight(long beg, long len) {
  5376. if (beg > realLength || beg < 0 || len < 0) return getRuntime().getNil();
  5377. if (beg + len > realLength) {
  5378. len = realLength - beg;
  5379. if (len < 0) len = 0;
  5380. }
  5381. if (len == 0) return new RubyArray(getRuntime(), getMetaClass(), 0, false);
  5382. return makeShared(begin + (int) beg, (int) len, getMetaClass(), false);
  5383. }
  5384. /** rb_ary_length
  5385. *
  5386. */
  5387. @JRubyMethod(name = "length", alias = "size")
  5388. public RubyFixnum length() {
  5389. return getRuntime().newFixnum(realLength);
  5390. }
  5391. /** rb_ary_push - specialized rb_ary_store
  5392. *
  5393. */
  5394. @JRubyMethod(name = "<<", required = 1)
  5395. public RubyArray append(IRubyObject item) {
  5396. modify();
  5397. if (realLength == values.length) {
  5398. if (realLength == Integer.MAX_VALUE) throw getRuntime().newArgumentError("index too big");
  5399. long newLength = values.length + (values.length >> 1);
  5400. if ( newLength > Integer.MAX_VALUE ) {
  5401. newLength = Integer.MAX_VALUE;
  5402. }else if ( newLength < ARRAY_DEFAULT_SIZE ) {
  5403. newLength = ARRAY_DEFAULT_SIZE;
  5404. }
  5405. realloc((int) newLength);
  5406. }
  5407. try {
  5408. values[realLength++] = item;
  5409. } catch (ArrayIndexOutOfBoundsException e) {
  5410. concurrentModification();
  5411. }
  5412. return this;
  5413. }
  5414. /** rb_ary_push_m
  5415. * FIXME: Whis is this named "push_m"?
  5416. */
  5417. @JRubyMethod(name = "push", rest = true)
  5418. public RubyArray push_m(IRubyObject[] items) {
  5419. for (int i = 0; i < items.length; i++) {
  5420. append(items[i]);
  5421. }
  5422. return this;
  5423. }
  5424. /** rb_ary_pop
  5425. *
  5426. */
  5427. @JRubyMethod(name = "pop")
  5428. public IRubyObject pop() {
  5429. modifyCheck();
  5430. if (realLength == 0) return getRuntime().getNil();
  5431. if (isShared) {
  5432. try {
  5433. return values[begin + --realLength];
  5434. } catch (ArrayIndexOutOfBoundsException e) {
  5435. concurrentModification();
  5436. return getRuntime().getNil();
  5437. }
  5438. } else {
  5439. int index = begin + --realLength;
  5440. try {
  5441. final IRubyObject obj = values[index];
  5442. values[index] = getRuntime().getNil();
  5443. return obj;
  5444. } catch (ArrayIndexOutOfBoundsException e) {
  5445. concurrentModification();
  5446. return getRuntime().getNil();
  5447. }
  5448. }
  5449. }
  5450. /** rb_ary_shift
  5451. *
  5452. */
  5453. @JRubyMethod(name = "shift")
  5454. public IRubyObject shift() {
  5455. modify();
  5456. if (realLength == 0) return getRuntime().getNil();
  5457. final IRubyObject obj;
  5458. try {
  5459. obj = values[begin];
  5460. values[begin] = getRuntime().getNil();
  5461. } catch (ArrayIndexOutOfBoundsException e) {
  5462. concurrentModification();
  5463. return getRuntime().getNil();
  5464. }
  5465. isShared = true;
  5466. begin++;
  5467. realLength--;
  5468. return obj;
  5469. }
  5470. /** rb_ary_unshift
  5471. *
  5472. */
  5473. public RubyArray unshift(IRubyObject item) {
  5474. modify();
  5475. if (realLength == values.length) {
  5476. int newLength = values.length >> 1;
  5477. if (newLength < ARRAY_DEFAULT_SIZE) newLength = ARRAY_DEFAULT_SIZE;
  5478. newLength += values.length;
  5479. realloc(newLength);
  5480. }
  5481. try {
  5482. System.arraycopy(values, 0, values, 1, realLength);
  5483. } catch (ArrayIndexOutOfBoundsException e) {
  5484. concurrentModification();
  5485. }
  5486. realLength++;
  5487. values[0] = item;
  5488. return this;
  5489. }
  5490. /** rb_ary_unshift_m
  5491. *
  5492. */
  5493. @JRubyMethod(name = "unshift", rest = true)
  5494. public RubyArray unshift_m(IRubyObject[] items) {
  5495. long len = realLength;
  5496. if (items.length == 0) return this;
  5497. store(len + items.length - 1, getRuntime().getNil());
  5498. try {
  5499. // it's safe to use zeroes here since modified by store()
  5500. System.arraycopy(values, 0, values, items.length, (int) len);
  5501. System.arraycopy(items, 0, values, 0, items.length);
  5502. } catch (ArrayIndexOutOfBoundsException e) {
  5503. concurrentModification();
  5504. }
  5505. return this;
  5506. }
  5507. /** rb_ary_includes
  5508. *
  5509. */
  5510. @JRubyMethod(name = "include?", required = 1)
  5511. public RubyBoolean include_p(ThreadContext context, IRubyObject item) {
  5512. return context.getRuntime().newBoolean(includes(context, item));
  5513. }
  5514. /** rb_ary_frozen_p
  5515. *
  5516. */
  5517. @JRubyMethod(name = "frozen?")
  5518. @Override
  5519. public RubyBoolean frozen_p(ThreadContext context) {
  5520. return context.getRuntime().newBoolean(isFrozen() || (flags & TMPLOCK_ARR_F) != 0);
  5521. }
  5522. /**
  5523. * Variable arity version for compatibility. Not bound to a Ruby method.
  5524. * @deprecated Use the versions with zero, one, or two args.
  5525. */
  5526. public IRubyObject aref(IRubyObject[] args) {
  5527. switch (args.length) {
  5528. case 1:
  5529. return aref(args[0]);
  5530. case 2:
  5531. return aref(args[0], args[1]);
  5532. default:
  5533. Arity.raiseArgumentError(getRuntime(), args.length, 1, 2);
  5534. return null; // not reached
  5535. }
  5536. }
  5537. /** rb_ary_aref
  5538. */
  5539. @JRubyMethod(name = {"[]", "slice"})
  5540. public IRubyObject aref(IRubyObject arg0) {
  5541. if (arg0 instanceof RubyFixnum) return entry(((RubyFixnum)arg0).getLongValue());
  5542. if (arg0 instanceof RubySymbol) throw getRuntime().newTypeError("Symbol as array index");
  5543. long[] beglen;
  5544. if (!(arg0 instanceof RubyRange)) {
  5545. } else if ((beglen = ((RubyRange) arg0).begLen(realLength, 0)) == null) {
  5546. return getRuntime().getNil();
  5547. } else {
  5548. return subseq(beglen[0], beglen[1]);
  5549. }
  5550. return entry(RubyNumeric.num2long(arg0));
  5551. }
  5552. /** rb_ary_aref
  5553. */
  5554. @JRubyMethod(name = {"[]", "slice"})
  5555. public IRubyObject aref(IRubyObject arg0, IRubyObject arg1) {
  5556. if (arg0 instanceof RubySymbol) throw getRuntime().newTypeError("Symbol as array index");
  5557. long beg = RubyNumeric.num2long(arg0);
  5558. if (beg < 0) beg += realLength;
  5559. return subseq(beg, RubyNumeric.num2long(arg1));
  5560. }
  5561. /**
  5562. * Variable arity version for compatibility. Not bound to a Ruby method.
  5563. * @deprecated Use the versions with zero, one, or two args.
  5564. */
  5565. public IRubyObject aset(IRubyObject[] args) {
  5566. switch (args.length) {
  5567. case 2:
  5568. return aset(args[0], args[1]);
  5569. case 3:
  5570. return aset(args[0], args[1], args[2]);
  5571. default:
  5572. throw getRuntime().newArgumentError("wrong number of arguments (" + args.length + " for 2)");
  5573. }
  5574. }
  5575. /** rb_ary_aset
  5576. *
  5577. */
  5578. @JRubyMethod(name = "[]=")
  5579. public IRubyObject aset(IRubyObject arg0, IRubyObject arg1) {
  5580. if (arg0 instanceof RubyFixnum) {
  5581. store(((RubyFixnum)arg0).getLongValue(), arg1);
  5582. return arg1;
  5583. }
  5584. if (arg0 instanceof RubyRange) {
  5585. long[] beglen = ((RubyRange) arg0).begLen(realLength, 1);
  5586. splice(beglen[0], beglen[1], arg1);
  5587. return arg1;
  5588. }
  5589. if (arg0 instanceof RubySymbol) throw getRuntime().newTypeError("Symbol as array index");
  5590. store(RubyNumeric.num2long(arg0), arg1);
  5591. return arg1;
  5592. }
  5593. /** rb_ary_aset
  5594. *
  5595. */
  5596. @JRubyMethod(name = "[]=")
  5597. public IRubyObject aset(IRubyObject arg0, IRubyObject arg1, IRubyObject arg2) {
  5598. if (arg0 instanceof RubySymbol) throw getRuntime().newTypeError("Symbol as array index");
  5599. if (arg1 instanceof RubySymbol) throw getRuntime().newTypeError("Symbol as subarray length");
  5600. splice(RubyNumeric.num2long(arg0), RubyNumeric.num2long(arg1), arg2);
  5601. return arg2;
  5602. }
  5603. /** rb_ary_at
  5604. *
  5605. */
  5606. @JRubyMethod(name = "at", required = 1)
  5607. public IRubyObject at(IRubyObject pos) {
  5608. return entry(RubyNumeric.num2long(pos));
  5609. }
  5610. /** rb_ary_concat
  5611. *
  5612. */
  5613. @JRubyMethod(name = "concat", required = 1)
  5614. public RubyArray concat(IRubyObject obj) {
  5615. RubyArray ary = obj.convertToArray();
  5616. if (ary.realLength > 0) splice(realLength, 0, ary);
  5617. return this;
  5618. }
  5619. /** inspect_ary
  5620. *
  5621. */
  5622. private IRubyObject inspectAry(ThreadContext context) {
  5623. ByteList buffer = new ByteList();
  5624. buffer.append('[');
  5625. boolean tainted = isTaint();
  5626. for (int i = 0; i < realLength; i++) {
  5627. if (i > 0) buffer.append(',').append(' ');
  5628. RubyString str = inspect(context, values[begin + i]);
  5629. if (str.isTaint()) tainted = true;
  5630. buffer.append(str.getByteList());
  5631. }
  5632. buffer.append(']');
  5633. RubyString str = getRuntime().newString(buffer);
  5634. if (tainted) str.setTaint(true);
  5635. return str;
  5636. }
  5637. /** rb_ary_inspect
  5638. *
  5639. */
  5640. @JRubyMethod(name = "inspect")
  5641. @Override
  5642. public IRubyObject inspect() {
  5643. if (realLength == 0) return getRuntime().newString("[]");
  5644. if (getRuntime().isInspecting(this)) return getRuntime().newString("[...]");
  5645. try {
  5646. getRuntime().registerInspecting(this);
  5647. return inspectAry(getRuntime().getCurrentContext());
  5648. } finally {
  5649. getRuntime().unregisterInspecting(this);
  5650. }
  5651. }
  5652. /**
  5653. * Variable arity version for compatibility. Not bound to a Ruby method.
  5654. * @deprecated Use the versions with zero, one, or two args.
  5655. */
  5656. public IRubyObject first(IRubyObject[] args) {
  5657. switch (args.length) {
  5658. case 0:
  5659. return first();
  5660. case 1:
  5661. return first(args[0]);
  5662. default:
  5663. Arity.raiseArgumentError(getRuntime(), args.length, 0, 1);
  5664. return null; // not reached
  5665. }
  5666. }
  5667. /** rb_ary_first
  5668. *
  5669. */
  5670. @JRubyMethod(name = "first")
  5671. public IRubyObject first() {
  5672. if (realLength == 0) return getRuntime().getNil();
  5673. return values[begin];
  5674. }
  5675. /** rb_ary_first
  5676. *
  5677. */
  5678. @JRubyMethod(name = "first")
  5679. public IRubyObject first(IRubyObject arg0) {
  5680. long n = RubyNumeric.num2long(arg0);
  5681. if (n > realLength) {
  5682. n = realLength;
  5683. } else if (n < 0) {
  5684. throw getRuntime().newArgumentError("negative array size (or size too big)");
  5685. }
  5686. return makeShared(begin, (int) n, getRuntime().getArray());
  5687. }
  5688. /**
  5689. * Variable arity version for compatibility. Not bound to a Ruby method.
  5690. * @deprecated Use the versions with zero, one, or two args.
  5691. */
  5692. public IRubyObject last(IRubyObject[] args) {
  5693. switch (args.length) {
  5694. case 0:
  5695. return last();
  5696. case 1:
  5697. return last(args[0]);
  5698. default:
  5699. Arity.raiseArgumentError(getRuntime(), args.length, 0, 1);
  5700. return null; // not reached
  5701. }
  5702. }
  5703. /** rb_ary_last
  5704. *
  5705. */
  5706. @JRubyMethod(name = "last")
  5707. public IRubyObject last() {
  5708. if (realLength == 0) return getRuntime().getNil();
  5709. return values[begin + realLength - 1];
  5710. }
  5711. /** rb_ary_last
  5712. *
  5713. */
  5714. @JRubyMethod(name = "last")
  5715. public IRubyObject last(IRubyObject arg0) {
  5716. long n = RubyNumeric.num2long(arg0);
  5717. if (n > realLength) {
  5718. n = realLength;
  5719. } else if (n < 0) {
  5720. throw getRuntime().newArgumentError("negative array size (or size too big)");
  5721. }
  5722. return makeShared(begin + realLength - (int) n, (int) n, getRuntime().getArray());
  5723. }
  5724. /** rb_ary_each
  5725. *
  5726. */
  5727. @JRubyMethod(name = "each", frame = true)
  5728. public IRubyObject each(ThreadContext context, Block block) {
  5729. for (int i = 0; i < realLength; i++) {
  5730. block.yield(context, values[begin + i]);
  5731. }
  5732. return this;
  5733. }
  5734. /** rb_ary_each_index
  5735. *
  5736. */
  5737. @JRubyMethod(name = "each_index", frame = true)
  5738. public IRubyObject each_index(ThreadContext context, Block block) {
  5739. Ruby runtime = getRuntime();
  5740. for (int i = 0; i < realLength; i++) {
  5741. block.yield(context, runtime.newFixnum(i));
  5742. }
  5743. return this;
  5744. }
  5745. /** rb_ary_reverse_each
  5746. *
  5747. */
  5748. @JRubyMethod(name = "reverse_each", frame = true)
  5749. public IRubyObject reverse_each(ThreadContext context, Block block) {
  5750. int len = realLength;
  5751. while(len-- > 0) {
  5752. block.yield(context, values[begin + len]);
  5753. if (realLength < len) len = realLength;
  5754. }
  5755. return this;
  5756. }
  5757. private IRubyObject inspectJoin(ThreadContext context, RubyArray tmp, IRubyObject sep) {
  5758. Ruby runtime = getRuntime();
  5759. // If already inspecting, there is no need to register/unregister again.
  5760. if (runtime.isInspecting(this)) {
  5761. return tmp.join(context, sep);
  5762. }
  5763. try {
  5764. runtime.registerInspecting(this);
  5765. return tmp.join(context, sep);
  5766. } finally {
  5767. runtime.unregisterInspecting(this);
  5768. }
  5769. }
  5770. /** rb_ary_join
  5771. *
  5772. */
  5773. public RubyString join(ThreadContext context, IRubyObject sep) {
  5774. final Ruby runtime = getRuntime();
  5775. if (realLength == 0) return RubyString.newEmptyString(getRuntime());
  5776. boolean taint = isTaint() || sep.isTaint();
  5777. long len = 1;
  5778. for (int i = begin; i < begin + realLength; i++) {
  5779. IRubyObject value;
  5780. try {
  5781. value = values[i];
  5782. } catch (ArrayIndexOutOfBoundsException e) {
  5783. concurrentModification();
  5784. return runtime.newString("");
  5785. }
  5786. IRubyObject tmp = value.checkStringType();
  5787. len += tmp.isNil() ? 10 : ((RubyString) tmp).getByteList().length();
  5788. }
  5789. RubyString strSep = null;
  5790. if (!sep.isNil()) {
  5791. sep = strSep = sep.convertToString();
  5792. len += strSep.getByteList().length() * (realLength - 1);
  5793. }
  5794. ByteList buf = new ByteList((int)len);
  5795. for (int i = begin; i < begin + realLength; i++) {
  5796. IRubyObject tmp;
  5797. try {
  5798. tmp = values[i];
  5799. } catch (ArrayIndexOutOfBoundsException e) {
  5800. concurrentModification();
  5801. return runtime.newString("");
  5802. }
  5803. if (tmp instanceof RubyString) {
  5804. // do nothing
  5805. } else if (tmp instanceof RubyArray) {
  5806. if (runtime.isInspecting(tmp)) {
  5807. tmp = runtime.newString("[...]");
  5808. } else {
  5809. tmp = inspectJoin(context, (RubyArray)tmp, sep);
  5810. }
  5811. } else {
  5812. tmp = RubyString.objAsString(context, tmp);
  5813. }
  5814. if (i > begin && !sep.isNil()) buf.append(strSep.getByteList());
  5815. buf.append(tmp.asString().getByteList());
  5816. if (tmp.isTaint()) taint = true;
  5817. }
  5818. RubyString result = runtime.newString(buf);
  5819. if (taint) result.setTaint(true);
  5820. return result;
  5821. }
  5822. /** rb_ary_join_m
  5823. *
  5824. */
  5825. @JRubyMethod(name = "join", optional = 1)
  5826. public RubyString join_m(ThreadContext context, IRubyObject[] args) {
  5827. int argc = args.length;
  5828. IRubyObject sep = (argc == 1) ? args[0] : getRuntime().getGlobalVariables().get("$,");
  5829. return join(context, sep);
  5830. }
  5831. /** rb_ary_to_a
  5832. *
  5833. */
  5834. @JRubyMethod(name = "to_a")
  5835. @Override
  5836. public RubyArray to_a() {
  5837. if(getMetaClass() != getRuntime().getArray()) {
  5838. RubyArray dup = new RubyArray(getRuntime(), getRuntime().isObjectSpaceEnabled());
  5839. isShared = true;
  5840. dup.isShared = true;
  5841. dup.values = values;
  5842. dup.realLength = realLength;
  5843. dup.begin = begin;
  5844. return dup;
  5845. }
  5846. return this;
  5847. }
  5848. @JRubyMethod(name = "to_ary")
  5849. public IRubyObject to_ary() {
  5850. return this;
  5851. }
  5852. @Override
  5853. public RubyArray convertToArray() {
  5854. return this;
  5855. }
  5856. @Override
  5857. public IRubyObject checkArrayType(){
  5858. return this;
  5859. }
  5860. /** rb_ary_equal
  5861. *
  5862. */
  5863. @JRubyMethod(name = "==", required = 1)
  5864. @Override
  5865. public IRubyObject op_equal(ThreadContext context, IRubyObject obj) {
  5866. if (this == obj) return getRuntime().getTrue();
  5867. if (!(obj instanceof RubyArray)) {
  5868. if (!obj.respondsTo("to_ary")) {
  5869. return getRuntime().getFalse();
  5870. } else {
  5871. if (equalInternal(context, obj.callMethod(context, "to_ary"), this)) return getRuntime().getTrue();
  5872. return getRuntime().getFalse();
  5873. }
  5874. }
  5875. RubyArray ary = (RubyArray) obj;
  5876. if (realLength != ary.realLength) return getRuntime().getFalse();
  5877. Ruby runtime = getRuntime();
  5878. for (long i = 0; i < realLength; i++) {
  5879. if (!equalInternal(context, elt(i), ary.elt(i))) return runtime.getFalse();
  5880. }
  5881. return runtime.getTrue();
  5882. }
  5883. /** rb_ary_eql
  5884. *
  5885. */
  5886. @JRubyMethod(name = "eql?", required = 1)
  5887. public RubyBoolean eql_p(ThreadContext context, IRubyObject obj) {
  5888. if (this == obj) return getRuntime().getTrue();
  5889. if (!(obj instanceof RubyArray)) return getRuntime().getFalse();
  5890. RubyArray ary = (RubyArray) obj;
  5891. if (realLength != ary.realLength) return getRuntime().getFalse();
  5892. Ruby runtime = getRuntime();
  5893. for (int i = 0; i < realLength; i++) {
  5894. if (!eqlInternal(context, elt(i), ary.elt(i))) return runtime.getFalse();
  5895. }
  5896. return runtime.getTrue();
  5897. }
  5898. /** rb_ary_compact_bang
  5899. *
  5900. */
  5901. @JRubyMethod(name = "compact!")
  5902. public IRubyObject compact_bang() {
  5903. modify();
  5904. int p = 0;
  5905. int t = 0;
  5906. int end = p + realLength;
  5907. while (t < end) {
  5908. if (values[t].isNil()) {
  5909. t++;
  5910. } else {
  5911. values[p++] = values[t++];
  5912. }
  5913. }
  5914. if (realLength == p) return getRuntime().getNil();
  5915. realloc(p);
  5916. realLength = p;
  5917. return this;
  5918. }
  5919. /** rb_ary_compact
  5920. *
  5921. */
  5922. @JRubyMethod(name = "compact")
  5923. public IRubyObject compact() {
  5924. RubyArray ary = aryDup();
  5925. ary.compact_bang();
  5926. return ary;
  5927. }
  5928. /** rb_ary_empty_p
  5929. *
  5930. */
  5931. @JRubyMethod(name = "empty?")
  5932. public IRubyObject empty_p() {
  5933. return realLength == 0 ? getRuntime().getTrue() : getRuntime().getFalse();
  5934. }
  5935. /** rb_ary_clear
  5936. *
  5937. */
  5938. @JRubyMethod(name = "clear")
  5939. public IRubyObject rb_clear() {
  5940. modifyCheck();
  5941. if(isShared) {
  5942. alloc(ARRAY_DEFAULT_SIZE);
  5943. isShared = true;
  5944. } else if (values.length > ARRAY_DEFAULT_SIZE << 1){
  5945. alloc(ARRAY_DEFAULT_SIZE << 1);
  5946. } else {
  5947. final int begin = this.begin;
  5948. try {
  5949. Arrays.fill(values, begin, begin + realLength, getRuntime().getNil());
  5950. } catch (ArrayIndexOutOfBoundsException e) {
  5951. concurrentModification();
  5952. }
  5953. }
  5954. begin = 0;
  5955. realLength = 0;
  5956. return this;
  5957. }
  5958. /** rb_ary_fill
  5959. *
  5960. */
  5961. @JRubyMethod(name = "fill", optional = 3, frame = true)
  5962. public IRubyObject fill(ThreadContext context, IRubyObject[] args, Block block) {
  5963. IRubyObject item = null;
  5964. IRubyObject begObj = null;
  5965. IRubyObject lenObj = null;
  5966. int argc = args.length;
  5967. if (block.isGiven()) {
  5968. Arity.checkArgumentCount(getRuntime(), args, 0, 2);
  5969. item = null;
  5970. begObj = argc > 0 ? args[0] : null;
  5971. lenObj = argc > 1 ? args[1] : null;
  5972. argc++;
  5973. } else {
  5974. Arity.checkArgumentCount(getRuntime(), args, 1, 3);
  5975. item = args[0];
  5976. begObj = argc > 1 ? args[1] : null;
  5977. lenObj = argc > 2 ? args[2] : null;
  5978. }
  5979. int beg = 0, end = 0, len = 0;
  5980. switch (argc) {
  5981. case 1:
  5982. beg = 0;
  5983. len = realLength;
  5984. break;
  5985. case 2:
  5986. if (begObj instanceof RubyRange) {
  5987. long[] beglen = ((RubyRange) begObj).begLen(realLength, 1);
  5988. beg = (int) beglen[0];
  5989. len = (int) beglen[1];
  5990. break;
  5991. }
  5992. /* fall through */
  5993. case 3:
  5994. beg = begObj.isNil() ? 0 : RubyNumeric.num2int(begObj);
  5995. if (beg < 0) {
  5996. beg = realLength + beg;
  5997. if (beg < 0) beg = 0;
  5998. }
  5999. len = (lenObj == null || lenObj.isNil()) ? realLength - beg : RubyNumeric.num2int(lenObj);
  6000. // TODO: In MRI 1.9, an explicit check for negative length is
  6001. // added here. IndexError is raised when length is negative.
  6002. // See [ruby-core:12953] for more details.
  6003. //
  6004. // New note: This is actually under re-evaluation,
  6005. // see [ruby-core:17483].
  6006. break;
  6007. }
  6008. modify();
  6009. // See [ruby-core:17483]
  6010. if (len < 0) {
  6011. return this;
  6012. }
  6013. if (len > Integer.MAX_VALUE - beg) {
  6014. throw getRuntime().newArgumentError("argument too big");
  6015. }
  6016. end = beg + len;
  6017. if (end > realLength) {
  6018. if (end >= values.length) realloc(end);
  6019. realLength = end;
  6020. }
  6021. if (block.isGiven()) {
  6022. Ruby runtime = getRuntime();
  6023. for (int i = beg; i < end; i++) {
  6024. IRubyObject v = block.yield(context, runtime.newFixnum(i));
  6025. if (i >= realLength) break;
  6026. try {
  6027. values[i] = v;
  6028. } catch (ArrayIndexOutOfBoundsException e) {
  6029. concurrentModification();
  6030. }
  6031. }
  6032. } else {
  6033. if (len > 0) {
  6034. try {
  6035. Arrays.fill(values, beg, beg + len, item);
  6036. } catch (ArrayIndexOutOfBoundsException e) {
  6037. concurrentModification();
  6038. }
  6039. }
  6040. }
  6041. return this;
  6042. }
  6043. /** rb_ary_index
  6044. *
  6045. */
  6046. @JRubyMethod(name = "index", required = 1)
  6047. public IRubyObject index(ThreadContext context, IRubyObject obj) {
  6048. Ruby runtime = getRuntime();
  6049. for (int i = begin; i < begin + realLength; i++) {
  6050. if (equalInternal(context, values[i], obj)) return runtime.newFixnum(i - begin);
  6051. }
  6052. return runtime.getNil();
  6053. }
  6054. /** rb_ary_rindex
  6055. *
  6056. */
  6057. @JRubyMethod(name = "rindex", required = 1)
  6058. public IRubyObject rindex(ThreadContext context, IRubyObject obj) {
  6059. Ruby runtime = getRuntime();
  6060. int i = realLength;
  6061. while (i-- > 0) {
  6062. if (i > realLength) {
  6063. i = realLength;
  6064. continue;
  6065. }
  6066. if (equalInternal(context, values[begin + i], obj)) return getRuntime().newFixnum(i);
  6067. }
  6068. return runtime.getNil();
  6069. }
  6070. /** rb_ary_indexes
  6071. *
  6072. */
  6073. @JRubyMethod(name = {"indexes", "indices"}, required = 1, rest = true)
  6074. public IRubyObject indexes(IRubyObject[] args) {
  6075. getRuntime().getWarnings().warn(ID.DEPRECATED_METHOD, "Array#indexes is deprecated; use Array#values_at", "Array#indexes", "Array#values_at");
  6076. RubyArray ary = new RubyArray(getRuntime(), args.length);
  6077. IRubyObject[] arefArgs = new IRubyObject[1];
  6078. for (int i = 0; i < args.length; i++) {
  6079. arefArgs[0] = args[i];
  6080. ary.append(aref(arefArgs));
  6081. }
  6082. return ary;
  6083. }
  6084. /** rb_ary_reverse_bang
  6085. *
  6086. */
  6087. @JRubyMethod(name = "reverse!")
  6088. public IRubyObject reverse_bang() {
  6089. modify();
  6090. final int realLength = this.realLength;
  6091. final IRubyObject[] values = this.values;
  6092. try {
  6093. if (realLength > 1) {
  6094. int p1 = 0;
  6095. int p2 = p1 + realLength - 1;
  6096. while (p1 < p2) {
  6097. final IRubyObject tmp = values[p1];
  6098. values[p1++] = values[p2];
  6099. values[p2--] = tmp;
  6100. }
  6101. }
  6102. } catch (ArrayIndexOutOfBoundsException e) {
  6103. concurrentModification();
  6104. }
  6105. return this;
  6106. }
  6107. /** rb_ary_reverse_m
  6108. *
  6109. */
  6110. @JRubyMethod(name = "reverse")
  6111. public IRubyObject reverse() {
  6112. return aryDup().reverse_bang();
  6113. }
  6114. /** rb_ary_collect
  6115. *
  6116. */
  6117. @JRubyMethod(name = {"collect", "map"}, frame = true)
  6118. public RubyArray collect(ThreadContext context, Block block) {
  6119. Ruby runtime = getRuntime();
  6120. if (!block.isGiven()) return new RubyArray(getRuntime(), runtime.getArray(), this);
  6121. RubyArray collect = new RubyArray(runtime, realLength);
  6122. for (int i = begin; i < begin + realLength; i++) {
  6123. collect.append(block.yield(context, values[i]));
  6124. }
  6125. return collect;
  6126. }
  6127. /** rb_ary_collect_bang
  6128. *
  6129. */
  6130. @JRubyMethod(name = {"collect!", "map!"}, frame = true)
  6131. public RubyArray collect_bang(ThreadContext context, Block block) {
  6132. modify();
  6133. for (int i = 0, len = realLength; i < len; i++) {
  6134. store(i, block.yield(context, values[begin + i]));
  6135. }
  6136. return this;
  6137. }
  6138. /** rb_ary_select
  6139. *
  6140. */
  6141. @JRubyMethod(name = "select", frame = true)
  6142. public RubyArray select(ThreadContext context, Block block) {
  6143. Ruby runtime = getRuntime();
  6144. RubyArray result = new RubyArray(runtime, realLength);
  6145. if (isShared) {
  6146. for (int i = begin; i < begin + realLength; i++) {
  6147. if (block.yield(context, values[i]).isTrue()) result.append(elt(i - begin));
  6148. }
  6149. } else {
  6150. for (int i = 0; i < realLength; i++) {
  6151. if (block.yield(context, values[i]).isTrue()) result.append(elt(i));
  6152. }
  6153. }
  6154. return result;
  6155. }
  6156. /** rb_ary_delete
  6157. *
  6158. */
  6159. @JRubyMethod(name = "delete", required = 1, frame = true)
  6160. public IRubyObject delete(ThreadContext context, IRubyObject item, Block block) {
  6161. int i2 = 0;
  6162. Ruby runtime = getRuntime();
  6163. for (int i1 = 0; i1 < realLength; i1++) {
  6164. IRubyObject e = values[begin + i1];
  6165. if (equalInternal(context, e, item)) continue;
  6166. if (i1 != i2) store(i2, e);
  6167. i2++;
  6168. }
  6169. if (realLength == i2) {
  6170. if (block.isGiven()) return block.yield(context, item);
  6171. return runtime.getNil();
  6172. }
  6173. modify();
  6174. final int realLength = this.realLength;
  6175. final int begin = this.begin;
  6176. final IRubyObject[] values = this.values;
  6177. if (realLength > i2) {
  6178. try {
  6179. Arrays.fill(values, begin + i2, begin + realLength, getRuntime().getNil());
  6180. } catch (ArrayIndexOutOfBoundsException e) {
  6181. concurrentModification();
  6182. }
  6183. this.realLength = i2;
  6184. if (i2 << 1 < values.length && values.length > ARRAY_DEFAULT_SIZE) realloc(i2 << 1);
  6185. }
  6186. return item;
  6187. }
  6188. /** rb_ary_delete_at
  6189. *
  6190. */
  6191. private final IRubyObject delete_at(int pos) {
  6192. int len = realLength;
  6193. if (pos >= len) return getRuntime().getNil();
  6194. if (pos < 0) pos += len;
  6195. if (pos < 0) return getRuntime().getNil();
  6196. modify();
  6197. IRubyObject obj = values[pos];
  6198. try {
  6199. System.arraycopy(values, pos + 1, values, pos, len - (pos + 1));
  6200. values[realLength-1] = getRuntime().getNil();
  6201. } catch (ArrayIndexOutOfBoundsException e) {
  6202. concurrentModification();
  6203. }
  6204. realLength--;
  6205. return obj;
  6206. }
  6207. /** rb_ary_delete_at_m
  6208. *
  6209. */
  6210. @JRubyMethod(name = "delete_at", required = 1)
  6211. public IRubyObject delete_at(IRubyObject obj) {
  6212. return delete_at((int) RubyNumeric.num2long(obj));
  6213. }
  6214. /** rb_ary_reject_bang
  6215. *
  6216. */
  6217. @JRubyMethod(name = "reject", frame = true)
  6218. public IRubyObject reject(ThreadContext context, Block block) {
  6219. RubyArray ary = aryDup();
  6220. ary.reject_bang(context, block);
  6221. return ary;
  6222. }
  6223. /** rb_ary_reject_bang
  6224. *
  6225. */
  6226. @JRubyMethod(name = "reject!", frame = true)
  6227. public IRubyObject reject_bang(ThreadContext context, Block block) {
  6228. int i2 = 0;
  6229. modify();
  6230. for (int i1 = 0; i1 < realLength; i1++) {
  6231. IRubyObject v = values[i1];
  6232. if (block.yield(context, v).isTrue()) continue;
  6233. if (i1 != i2) store(i2, v);
  6234. i2++;
  6235. }
  6236. if (realLength == i2) return getRuntime().getNil();
  6237. if (i2 < realLength) {
  6238. try {
  6239. Arrays.fill(values, i2, realLength, getRuntime().getNil());
  6240. } catch (ArrayIndexOutOfBoundsException e) {
  6241. concurrentModification();
  6242. }
  6243. realLength = i2;
  6244. }
  6245. return this;
  6246. }
  6247. /** rb_ary_delete_if
  6248. *
  6249. */
  6250. @JRubyMethod(name = "delete_if", frame = true)
  6251. public IRubyObject delete_if(ThreadContext context, Block block) {
  6252. reject_bang(context, block);
  6253. return this;
  6254. }
  6255. /** rb_ary_zip
  6256. *
  6257. */
  6258. @JRubyMethod(name = "zip", optional = 1, rest = true, frame = true)
  6259. public IRubyObject zip(ThreadContext context, IRubyObject[] args, Block block) {
  6260. for (int i = 0; i < args.length; i++) {
  6261. args[i] = args[i].convertToArray();
  6262. }
  6263. Ruby runtime = getRuntime();
  6264. if (block.isGiven()) {
  6265. for (int i = 0; i < realLength; i++) {
  6266. RubyArray tmp = new RubyArray(runtime, args.length + 1);
  6267. tmp.append(elt(i));
  6268. for (int j = 0; j < args.length; j++) {
  6269. tmp.append(((RubyArray) args[j]).elt(i));
  6270. }
  6271. block.yield(context, tmp);
  6272. }
  6273. return runtime.getNil();
  6274. }
  6275. int len = realLength;
  6276. RubyArray result = new RubyArray(runtime, len);
  6277. for (int i = 0; i < len; i++) {
  6278. RubyArray tmp = new RubyArray(runtime, args.length + 1);
  6279. tmp.append(elt(i));
  6280. for (int j = 0; j < args.length; j++) {
  6281. tmp.append(((RubyArray) args[j]).elt(i));
  6282. }
  6283. result.append(tmp);
  6284. }
  6285. return result;
  6286. }
  6287. /** rb_ary_cmp
  6288. *
  6289. */
  6290. @JRubyMethod(name = "<=>", required = 1)
  6291. public IRubyObject op_cmp(ThreadContext context, IRubyObject obj) {
  6292. RubyArray ary2 = obj.convertToArray();
  6293. int len = realLength;
  6294. if (len > ary2.realLength) len = ary2.realLength;
  6295. Ruby runtime = getRuntime();
  6296. for (int i = 0; i < len; i++) {
  6297. IRubyObject v = elt(i).callMethod(context, MethodIndex.OP_SPACESHIP, "<=>", ary2.elt(i));
  6298. if (!(v instanceof RubyFixnum) || ((RubyFixnum) v).getLongValue() != 0) return v;
  6299. }
  6300. len = realLength - ary2.realLength;
  6301. if (len == 0) return RubyFixnum.zero(runtime);
  6302. if (len > 0) return RubyFixnum.one(runtime);
  6303. return RubyFixnum.minus_one(runtime);
  6304. }
  6305. /**
  6306. * Variable arity version for compatibility. Not bound to a Ruby method.
  6307. * @deprecated Use the versions with zero, one, or two args.
  6308. */
  6309. public IRubyObject slice_bang(IRubyObject[] args) {
  6310. switch (args.length) {
  6311. case 1:
  6312. return slice_bang(args[0]);
  6313. case 2:
  6314. return slice_bang(args[0], args[1]);
  6315. default:
  6316. Arity.raiseArgumentError(getRuntime(), args.length, 1, 2);
  6317. return null; // not reached
  6318. }
  6319. }
  6320. /** rb_ary_slice_bang
  6321. *
  6322. */
  6323. @JRubyMethod(name = "slice!")
  6324. public IRubyObject slice_bang(IRubyObject arg0) {
  6325. if (arg0 instanceof RubyRange) {
  6326. long[] beglen = ((RubyRange) arg0).begLen(realLength, 1);
  6327. long pos = beglen[0];
  6328. long len = beglen[1];
  6329. if (pos < 0) pos = realLength + pos;
  6330. arg0 = subseq(pos, len);
  6331. splice(pos, len, null);
  6332. return arg0;
  6333. }
  6334. return delete_at((int) RubyNumeric.num2long(arg0));
  6335. }
  6336. /** rb_ary_slice_bang
  6337. *
  6338. */
  6339. @JRubyMethod(name = "slice!")
  6340. public IRubyObject slice_bang(IRubyObject arg0, IRubyObject arg1) {
  6341. long pos = RubyNumeric.num2long(arg0);
  6342. long len = RubyNumeric.num2long(arg1);
  6343. if (pos < 0) pos = realLength + pos;
  6344. arg1 = subseq(pos, len);
  6345. splice(pos, len, null);
  6346. return arg1;
  6347. }
  6348. /** rb_ary_assoc
  6349. *
  6350. */
  6351. @JRubyMethod(name = "assoc", required = 1)
  6352. public IRubyObject assoc(ThreadContext context, IRubyObject key) {
  6353. Ruby runtime = getRuntime();
  6354. for (int i = begin; i < begin + realLength; i++) {
  6355. IRubyObject v = values[i];
  6356. if (v instanceof RubyArray) {
  6357. RubyArray arr = (RubyArray)v;
  6358. if (arr.realLength > 0 && equalInternal(context, arr.values[arr.begin], key)) return arr;
  6359. }
  6360. }
  6361. return runtime.getNil();
  6362. }
  6363. /** rb_ary_rassoc
  6364. *
  6365. */
  6366. @JRubyMethod(name = "rassoc", required = 1)
  6367. public IRubyObject rassoc(ThreadContext context, IRubyObject value) {
  6368. Ruby runtime = getRuntime();
  6369. for (int i = begin; i < begin + realLength; i++) {
  6370. IRubyObject v = values[i];
  6371. if (v instanceof RubyArray) {
  6372. RubyArray arr = (RubyArray)v;
  6373. if (arr.realLength > 1 && equalInternal(context, arr.values[arr.begin + 1], value)) return arr;
  6374. }
  6375. }
  6376. return runtime.getNil();
  6377. }
  6378. /** flatten
  6379. *
  6380. */
  6381. private final int flatten(ThreadContext context, int index, RubyArray ary2, RubyArray memo) {
  6382. int i = index;
  6383. int n;
  6384. int lim = index + ary2.realLength;
  6385. IRubyObject id = ary2.id();
  6386. if (memo.includes(context, id)) throw getRuntime().newArgumentError("tried to flatten recursive array");
  6387. memo.append(id);
  6388. splice(index, 1, ary2);
  6389. while (i < lim) {
  6390. IRubyObject tmp = elt(i).checkArrayType();
  6391. if (!tmp.isNil()) {
  6392. n = flatten(context, i, (RubyArray) tmp, memo);
  6393. i += n;
  6394. lim += n;
  6395. }
  6396. i++;
  6397. }
  6398. memo.pop();
  6399. return lim - index - 1; /* returns number of increased items */
  6400. }
  6401. /** rb_ary_flatten_bang
  6402. *
  6403. */
  6404. @JRubyMethod(name = "flatten!")
  6405. public IRubyObject flatten_bang(ThreadContext context) {
  6406. int i = 0;
  6407. RubyArray memo = null;
  6408. while (i < realLength) {
  6409. IRubyObject ary2 = values[begin + i];
  6410. IRubyObject tmp = ary2.checkArrayType();
  6411. if (!tmp.isNil()) {
  6412. if (memo == null) {
  6413. memo = new RubyArray(getRuntime(), false);
  6414. memo.values = reserve(ARRAY_DEFAULT_SIZE);
  6415. }
  6416. i += flatten(context, i, (RubyArray) tmp, memo);
  6417. }
  6418. i++;
  6419. }
  6420. if (memo == null) return getRuntime().getNil();
  6421. return this;
  6422. }
  6423. /** rb_ary_flatten
  6424. *
  6425. */
  6426. @JRubyMethod(name = "flatten")
  6427. public IRubyObject flatten(ThreadContext context) {
  6428. RubyArray ary = aryDup();
  6429. ary.flatten_bang(context);
  6430. return ary;
  6431. }
  6432. /** rb_ary_nitems
  6433. *
  6434. */
  6435. @JRubyMethod(name = "nitems")
  6436. public IRubyObject nitems() {
  6437. int n = 0;
  6438. for (int i = begin; i < begin + realLength; i++) {
  6439. if (!values[i].isNil()) n++;
  6440. }
  6441. return getRuntime().newFixnum(n);
  6442. }
  6443. /** rb_ary_plus
  6444. *
  6445. */
  6446. @JRubyMethod(name = "+", required = 1)
  6447. public IRubyObject op_plus(IRubyObject obj) {
  6448. RubyArray y = obj.convertToArray();
  6449. int len = realLength + y.realLength;
  6450. RubyArray z = new RubyArray(getRuntime(), len);
  6451. try {
  6452. System.arraycopy(values, begin, z.values, 0, realLength);
  6453. System.arraycopy(y.values, y.begin, z.values, realLength, y.realLength);
  6454. } catch (ArrayIndexOutOfBoundsException e) {
  6455. concurrentModification();
  6456. }
  6457. z.realLength = len;
  6458. return z;
  6459. }
  6460. /** rb_ary_times
  6461. *
  6462. */
  6463. @JRubyMethod(name = "*", required = 1)
  6464. public IRubyObject op_times(ThreadContext context, IRubyObject times) {
  6465. IRubyObject tmp = times.checkStringType();
  6466. if (!tmp.isNil()) return join(context, tmp);
  6467. long len = RubyNumeric.num2long(times);
  6468. if (len == 0) return new RubyArray(getRuntime(), getMetaClass(), 0);
  6469. if (len < 0) throw getRuntime().newArgumentError("negative argument");
  6470. if (Long.MAX_VALUE / len < realLength) {
  6471. throw getRuntime().newArgumentError("argument too big");
  6472. }
  6473. len *= realLength;
  6474. RubyArray ary2 = new RubyArray(getRuntime(), getMetaClass(), len);
  6475. ary2.realLength = (int) len;
  6476. try {
  6477. for (int i = 0; i < len; i += realLength) {
  6478. System.arraycopy(values, begin, ary2.values, i, realLength);
  6479. }
  6480. } catch (ArrayIndexOutOfBoundsException e) {
  6481. concurrentModification();
  6482. }
  6483. ary2.infectBy(this);
  6484. return ary2;
  6485. }
  6486. /** ary_make_hash
  6487. *
  6488. */
  6489. private final RubyHash makeHash(RubyArray ary2) {
  6490. RubyHash hash = new RubyHash(getRuntime(), false);
  6491. int begin = this.begin;
  6492. for (int i = begin; i < begin + realLength; i++) {
  6493. hash.fastASet(values[i], NEVER);
  6494. }
  6495. if (ary2 != null) {
  6496. begin = ary2.begin;
  6497. for (int i = begin; i < begin + ary2.realLength; i++) {
  6498. hash.fastASet(ary2.values[i], NEVER);
  6499. }
  6500. }
  6501. return hash;
  6502. }
  6503. /** rb_ary_uniq_bang
  6504. *
  6505. */
  6506. @JRubyMethod(name = "uniq!")
  6507. public IRubyObject uniq_bang() {
  6508. RubyHash hash = makeHash(null);
  6509. if (realLength == hash.size()) return getRuntime().getNil();
  6510. int j = 0;
  6511. for (int i = 0; i < realLength; i++) {
  6512. IRubyObject v = elt(i);
  6513. if (hash.fastDelete(v)) store(j++, v);
  6514. }
  6515. realLength = j;
  6516. return this;
  6517. }
  6518. /** rb_ary_uniq
  6519. *
  6520. */
  6521. @JRubyMethod(name = "uniq")
  6522. public IRubyObject uniq() {
  6523. RubyArray ary = aryDup();
  6524. ary.uniq_bang();
  6525. return ary;
  6526. }
  6527. /** rb_ary_diff
  6528. *
  6529. */
  6530. @JRubyMethod(name = "-", required = 1)
  6531. public IRubyObject op_diff(IRubyObject other) {
  6532. RubyHash hash = other.convertToArray().makeHash(null);
  6533. RubyArray ary3 = new RubyArray(getRuntime());
  6534. int begin = this.begin;
  6535. for (int i = begin; i < begin + realLength; i++) {
  6536. if (hash.fastARef(values[i]) != null) continue;
  6537. ary3.append(elt(i - begin));
  6538. }
  6539. return ary3;
  6540. }
  6541. /** rb_ary_and
  6542. *
  6543. */
  6544. @JRubyMethod(name = "&", required = 1)
  6545. public IRubyObject op_and(IRubyObject other) {
  6546. RubyArray ary2 = other.convertToArray();
  6547. RubyHash hash = ary2.makeHash(null);
  6548. RubyArray ary3 = new RubyArray(getRuntime(),
  6549. realLength < ary2.realLength ? realLength : ary2.realLength);
  6550. for (int i = 0; i < realLength; i++) {
  6551. IRubyObject v = elt(i);
  6552. if (hash.fastDelete(v)) ary3.append(v);
  6553. }
  6554. return ary3;
  6555. }
  6556. /** rb_ary_or
  6557. *
  6558. */
  6559. @JRubyMethod(name = "|", required = 1)
  6560. public IRubyObject op_or(IRubyObject other) {
  6561. RubyArray ary2 = other.convertToArray();
  6562. RubyHash set = makeHash(ary2);
  6563. RubyArray ary3 = new RubyArray(getRuntime(), realLength + ary2.realLength);
  6564. for (int i = 0; i < realLength; i++) {
  6565. IRubyObject v = elt(i);
  6566. if (set.fastDelete(v)) ary3.append(v);
  6567. }
  6568. for (int i = 0; i < ary2.realLength; i++) {
  6569. IRubyObject v = ary2.elt(i);
  6570. if (set.fastDelete(v)) ary3.append(v);
  6571. }
  6572. return ary3;
  6573. }
  6574. /** rb_ary_sort
  6575. *
  6576. */
  6577. @JRubyMethod(name = "sort", frame = true)
  6578. public RubyArray sort(Block block) {
  6579. RubyArray ary = aryDup();
  6580. ary.sort_bang(block);
  6581. return ary;
  6582. }
  6583. /** rb_ary_sort_bang
  6584. *
  6585. */
  6586. @JRubyMethod(name = "sort!", frame = true)
  6587. public RubyArray sort_bang(Block block) {
  6588. modify();
  6589. if (realLength > 1) {
  6590. flags |= TMPLOCK_ARR_F;
  6591. try {
  6592. if (block.isGiven()) {
  6593. Arrays.sort(values, 0, realLength, new BlockComparator(block));
  6594. } else {
  6595. Arrays.sort(values, 0, realLength, new DefaultComparator());
  6596. }
  6597. } finally {
  6598. flags &= ~TMPLOCK_ARR_F;
  6599. }
  6600. }
  6601. return this;
  6602. }
  6603. final class BlockComparator implements Comparator {
  6604. private Block block;
  6605. public BlockComparator(Block block) {
  6606. this.block = block;
  6607. }
  6608. public int compare(Object o1, Object o2) {
  6609. ThreadContext context = getRuntime().getCurrentContext();
  6610. IRubyObject obj1 = (IRubyObject) o1;
  6611. IRubyObject obj2 = (IRubyObject) o2;
  6612. IRubyObject ret = block.yield(context, getRuntime().newArray(obj1, obj2), null, null, true);
  6613. int n = RubyComparable.cmpint(context, ret, obj1, obj2);
  6614. //TODO: ary_sort_check should be done here
  6615. return n;
  6616. }
  6617. }
  6618. static final class DefaultComparator implements Comparator {
  6619. public int compare(Object o1, Object o2) {
  6620. if (o1 instanceof RubyFixnum && o2 instanceof RubyFixnum) {
  6621. return compareFixnums(o1, o2);
  6622. }
  6623. if (o1 instanceof RubyString && o2 instanceof RubyString) {
  6624. return ((RubyString) o1).op_cmp((RubyString) o2);
  6625. }
  6626. //TODO: ary_sort_check should be done here
  6627. return compareOthers((IRubyObject)o1, (IRubyObject)o2);
  6628. }
  6629. private int compareFixnums(Object o1, Object o2) {
  6630. long a = ((RubyFixnum) o1).getLongValue();
  6631. long b = ((RubyFixnum) o2).getLongValue();
  6632. if (a > b) {
  6633. return 1;
  6634. }
  6635. if (a < b) {
  6636. return -1;
  6637. }
  6638. return 0;
  6639. }
  6640. private int compareOthers(IRubyObject o1, IRubyObject o2) {
  6641. ThreadContext context = o1.getRuntime().getCurrentContext();
  6642. IRubyObject ret = o1.callMethod(context, MethodIndex.OP_SPACESHIP, "<=>", o2);
  6643. int n = RubyComparable.cmpint(context, ret, o1, o2);
  6644. //TODO: ary_sort_check should be done here
  6645. return n;
  6646. }
  6647. }
  6648. public static void marshalTo(RubyArray array, MarshalStream output) throws IOException {
  6649. output.registerLinkTarget(array);
  6650. output.writeInt(array.getList().size());
  6651. for (Iterator iter = array.getList().iterator(); iter.hasNext();) {
  6652. output.dumpObject((IRubyObject) iter.next());
  6653. }
  6654. }
  6655. public static RubyArray unmarshalFrom(UnmarshalStream input) throws IOException {
  6656. RubyArray result = input.getRuntime().newArray();
  6657. input.registerLinkTarget(result);
  6658. int size = input.unmarshalInt();
  6659. for (int i = 0; i < size; i++) {
  6660. result.append(input.unmarshalObject());
  6661. }
  6662. return result;
  6663. }
  6664. /**
  6665. * @see org.jruby.util.Pack#pack
  6666. */
  6667. @JRubyMethod(name = "pack", required = 1)
  6668. public RubyString pack(ThreadContext context, IRubyObject obj) {
  6669. RubyString iFmt = RubyString.objAsString(context, obj);
  6670. return Pack.pack(getRuntime(), this, iFmt.getByteList());
  6671. }
  6672. @Override
  6673. public Class getJavaClass() {
  6674. return List.class;
  6675. }
  6676. // Satisfy java.util.List interface (for Java integration)
  6677. public int size() {
  6678. return realLength;
  6679. }
  6680. public boolean isEmpty() {
  6681. return realLength == 0;
  6682. }
  6683. public boolean contains(Object element) {
  6684. return indexOf(element) != -1;
  6685. }
  6686. public Object[] toArray() {
  6687. Object[] array = new Object[realLength];
  6688. for (int i = begin; i < realLength; i++) {
  6689. array[i - begin] = JavaUtil.convertRubyToJava(values[i]);
  6690. }
  6691. return array;
  6692. }
  6693. public Object[] toArray(final Object[] arg) {
  6694. Object[] array = arg;
  6695. if (array.length < realLength) {
  6696. Class type = array.getClass().getComponentType();
  6697. array = (Object[]) Array.newInstance(type, realLength);
  6698. }
  6699. int length = realLength - begin;
  6700. for (int i = 0; i < length; i++) {
  6701. array[i] = JavaUtil.convertRubyToJava(values[i + begin]);
  6702. }
  6703. return array;
  6704. }
  6705. public boolean add(Object element) {
  6706. append(JavaUtil.convertJavaToRuby(getRuntime(), element));
  6707. return true;
  6708. }
  6709. public boolean remove(Object element) {
  6710. IRubyObject deleted = delete(getRuntime().getCurrentContext(), JavaUtil.convertJavaToRuby(getRuntime(), element), Block.NULL_BLOCK);
  6711. return deleted.isNil() ? false : true; // TODO: is this correct ?
  6712. }
  6713. public boolean containsAll(Collection c) {
  6714. for (Iterator iter = c.iterator(); iter.hasNext();) {
  6715. if (indexOf(iter.next()) == -1) {
  6716. return false;
  6717. }
  6718. }
  6719. return true;
  6720. }
  6721. public boolean addAll(Collection c) {
  6722. for (Iterator iter = c.iterator(); iter.hasNext();) {
  6723. add(iter.next());
  6724. }
  6725. return !c.isEmpty();
  6726. }
  6727. public boolean addAll(int index, Collection c) {
  6728. Iterator iter = c.iterator();
  6729. for (int i = index; iter.hasNext(); i++) {
  6730. add(i, iter.next());
  6731. }
  6732. return !c.isEmpty();
  6733. }
  6734. public boolean removeAll(Collection c) {
  6735. boolean listChanged = false;
  6736. for (Iterator iter = c.iterator(); iter.hasNext();) {
  6737. if (remove(iter.next())) {
  6738. listChanged = true;
  6739. }
  6740. }
  6741. return listChanged;
  6742. }
  6743. public boolean retainAll(Collection c) {
  6744. boolean listChanged = false;
  6745. for (Iterator iter = iterator(); iter.hasNext();) {
  6746. Object element = iter.next();
  6747. if (!c.contains(element)) {
  6748. remove(element);
  6749. listChanged = true;
  6750. }
  6751. }
  6752. return listChanged;
  6753. }
  6754. public Object get(int index) {
  6755. return JavaUtil.convertRubyToJava((IRubyObject) elt(index), Object.class);
  6756. }
  6757. public Object set(int index, Object element) {
  6758. return store(index, JavaUtil.convertJavaToRuby(getRuntime(), element));
  6759. }
  6760. // TODO: make more efficient by not creating IRubyArray[]
  6761. public void add(int index, Object element) {
  6762. insert(new IRubyObject[]{RubyFixnum.newFixnum(getRuntime(), index), JavaUtil.convertJavaToRuby(getRuntime(), element)});
  6763. }
  6764. public Object remove(int index) {
  6765. return JavaUtil.convertRubyToJava(delete_at(index), Object.class);
  6766. }
  6767. public int indexOf(Object element) {
  6768. int begin = this.begin;
  6769. if (element != null) {
  6770. IRubyObject convertedElement = JavaUtil.convertJavaToRuby(getRuntime(), element);
  6771. for (int i = begin; i < begin + realLength; i++) {
  6772. if (convertedElement.equals(values[i])) {
  6773. return i;
  6774. }
  6775. }
  6776. }
  6777. return -1;
  6778. }
  6779. public int lastIndexOf(Object element) {
  6780. int begin = this.begin;
  6781. if (element != null) {
  6782. IRubyObject convertedElement = JavaUtil.convertJavaToRuby(getRuntime(), element);
  6783. for (int i = begin + realLength - 1; i >= begin; i--) {
  6784. if (convertedElement.equals(values[i])) {
  6785. return i;
  6786. }
  6787. }
  6788. }
  6789. return -1;
  6790. }
  6791. public class RubyArrayConversionIterator implements Iterator {
  6792. protected int index = 0;
  6793. protected int last = -1;
  6794. public boolean hasNext() {
  6795. return index < realLength;
  6796. }
  6797. public Object next() {
  6798. IRubyObject element = elt(index);
  6799. last = index++;
  6800. return JavaUtil.convertRubyToJava(element, Object.class);
  6801. }
  6802. public void remove() {
  6803. if (last == -1) throw new IllegalStateException();
  6804. delete_at(last);
  6805. if (last < index) index--;
  6806. last = -1;
  6807. }
  6808. }
  6809. public Iterator iterator() {
  6810. return new RubyArrayConversionIterator();
  6811. }
  6812. final class RubyArrayConversionListIterator extends RubyArrayConversionIterator implements ListIterator {
  6813. public RubyArrayConversionListIterator() {
  6814. }
  6815. public RubyArrayConversionListIterator(int index) {
  6816. this.index = index;
  6817. }
  6818. public boolean hasPrevious() {
  6819. return index >= 0;
  6820. }
  6821. public Object previous() {
  6822. return JavaUtil.convertRubyToJava((IRubyObject) elt(last = --index), Object.class);
  6823. }
  6824. public int nextIndex() {
  6825. return index;
  6826. }
  6827. public int previousIndex() {
  6828. return index - 1;
  6829. }
  6830. public void set(Object obj) {
  6831. if (last == -1) throw new IllegalStateException();
  6832. store(last, JavaUtil.convertJavaToRuby(getRuntime(), obj));
  6833. }
  6834. public void add(Object obj) {
  6835. insert(new IRubyObject[] { RubyFixnum.newFixnum(getRuntime(), index++), JavaUtil.convertJavaToRuby(getRuntime(), obj) });
  6836. last = -1;
  6837. }
  6838. }
  6839. public ListIterator listIterator() {
  6840. return new RubyArrayConversionListIterator();
  6841. }
  6842. public ListIterator listIterator(int index) {
  6843. return new RubyArrayConversionListIterator(index);
  6844. }
  6845. // TODO: list.subList(from, to).clear() is supposed to clear the sublist from the list.
  6846. // How can we support this operation?
  6847. public List subList(int fromIndex, int toIndex) {
  6848. if (fromIndex < 0 || toIndex > size() || fromIndex > toIndex) {
  6849. throw new IndexOutOfBoundsException();
  6850. }
  6851. IRubyObject subList = subseq(fromIndex, toIndex - fromIndex + 1);
  6852. return subList.isNil() ? null : (List) subList;
  6853. }
  6854. public void clear() {
  6855. rb_clear();
  6856. }
  6857. }
  6858. /***** BEGIN LICENSE BLOCK *****
  6859. * Version: CPL 1.0/GPL 2.0/LGPL 2.1
  6860. *
  6861. * The contents of this file are subject to the Common Public
  6862. * License Version 1.0 (the "License"); you may not use this file
  6863. * except in compliance with the License. You may obtain a copy of
  6864. * the License at http://www.eclipse.org/legal/cpl-v10.html
  6865. *
  6866. * Software distributed under the License is distributed on an "AS
  6867. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  6868. * implied. See the License for the specific language governing
  6869. * rights and limitations under the License.
  6870. *
  6871. * Copyright (C) 2006 Ola Bini <ola@ologix.com>
  6872. *
  6873. * Alternatively, the contents of this file may be used under the terms of
  6874. * either of the GNU General Public License Version 2 or later (the "GPL"),
  6875. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  6876. * in which case the provisions of the GPL or the LGPL are applicable instead
  6877. * of those above. If you wish to allow use of your version of this file only
  6878. * under the terms of either the GPL or the LGPL, and not to allow others to
  6879. * use your version of this file under the terms of the CPL, indicate your
  6880. * decision by deleting the provisions above and replace them with the notice
  6881. * and other provisions required by the GPL or the LGPL. If you do not delete
  6882. * the provisions above, a recipient may use your version of this file under
  6883. * the terms of any one of the CPL, the GPL or the LGPL.
  6884. ***** END LICENSE BLOCK *****/
  6885. package org.jruby;
  6886. import java.math.BigDecimal;
  6887. import java.math.BigInteger;
  6888. import java.math.MathContext;
  6889. import java.math.RoundingMode;
  6890. import java.util.ArrayList;
  6891. import java.util.List;
  6892. import java.util.regex.Matcher;
  6893. import java.util.regex.Pattern;
  6894. import org.jruby.anno.JRubyClass;
  6895. import org.jruby.anno.JRubyConstant;
  6896. import org.jruby.anno.JRubyMethod;
  6897. import org.jruby.runtime.Arity;
  6898. import org.jruby.runtime.Block;
  6899. import org.jruby.runtime.CallbackFactory;
  6900. import org.jruby.runtime.MethodIndex;
  6901. import org.jruby.runtime.ObjectAllocator;
  6902. import org.jruby.runtime.ThreadContext;
  6903. import org.jruby.runtime.Visibility;
  6904. import org.jruby.runtime.builtin.IRubyObject;
  6905. /**
  6906. * @author <a href="mailto:ola.bini@ki.se">Ola Bini</a>
  6907. */
  6908. @JRubyClass(name="BigDecimal", parent="Numeric")
  6909. public class RubyBigDecimal extends RubyNumeric {
  6910. private static final ObjectAllocator BIGDECIMAL_ALLOCATOR = new ObjectAllocator() {
  6911. public IRubyObject allocate(Ruby runtime, RubyClass klass) {
  6912. return new RubyBigDecimal(runtime, klass);
  6913. }
  6914. };
  6915. @JRubyConstant
  6916. public final static int ROUND_DOWN = BigDecimal.ROUND_DOWN;
  6917. @JRubyConstant
  6918. public final static int ROUND_CEILING = BigDecimal.ROUND_CEILING;
  6919. @JRubyConstant
  6920. public final static int ROUND_UP = BigDecimal.ROUND_UP;
  6921. @JRubyConstant
  6922. public final static int ROUND_HALF_DOWN = BigDecimal.ROUND_HALF_DOWN;
  6923. @JRubyConstant
  6924. public final static int ROUND_HALF_EVEN = BigDecimal.ROUND_HALF_EVEN;
  6925. @JRubyConstant
  6926. public final static int ROUND_HALF_UP = BigDecimal.ROUND_HALF_UP;
  6927. @JRubyConstant
  6928. public final static int ROUND_FLOOR = BigDecimal.ROUND_FLOOR;
  6929. @JRubyConstant
  6930. public final static int SIGN_POSITIVE_INFINITE=3;
  6931. @JRubyConstant
  6932. public final static int EXCEPTION_OVERFLOW=1;
  6933. @JRubyConstant
  6934. public final static int SIGN_POSITIVE_ZERO=1;
  6935. @JRubyConstant
  6936. public final static int EXCEPTION_ALL=255;
  6937. @JRubyConstant
  6938. public final static int SIGN_NEGATIVE_FINITE=-2;
  6939. @JRubyConstant
  6940. public final static int EXCEPTION_UNDERFLOW=4;
  6941. @JRubyConstant
  6942. public final static int SIGN_NaN=0;
  6943. @JRubyConstant
  6944. public final static int BASE=10000;
  6945. @JRubyConstant
  6946. public final static int ROUND_MODE=256;
  6947. @JRubyConstant
  6948. public final static int SIGN_POSITIVE_FINITE=2;
  6949. @JRubyConstant
  6950. public final static int EXCEPTION_INFINITY=1;
  6951. @JRubyConstant
  6952. public final static int SIGN_NEGATIVE_INFINITE=-3;
  6953. @JRubyConstant
  6954. public final static int EXCEPTION_ZERODIVIDE=1;
  6955. @JRubyConstant
  6956. public final static int SIGN_NEGATIVE_ZERO=-1;
  6957. @JRubyConstant
  6958. public final static int EXCEPTION_NaN=2;
  6959. // Static constants
  6960. private static final BigDecimal TWO = new BigDecimal(2);
  6961. private static final double SQRT_10 = 3.162277660168379332;
  6962. public static RubyClass createBigDecimal(Ruby runtime) {
  6963. RubyClass result = runtime.defineClass("BigDecimal",runtime.getNumeric(), BIGDECIMAL_ALLOCATOR);
  6964. CallbackFactory callbackFactory = runtime.callbackFactory(RubyBigDecimal.class);
  6965. runtime.getKernel().defineAnnotatedMethods(BigDecimalKernelMethods.class);
  6966. result.setInternalModuleVariable("vpPrecLimit", RubyFixnum.zero(runtime));
  6967. result.setInternalModuleVariable("vpExceptionMode", RubyFixnum.zero(runtime));
  6968. result.setInternalModuleVariable("vpRoundingMode", runtime.newFixnum(ROUND_HALF_UP));
  6969. result.defineAnnotatedMethods(RubyBigDecimal.class);
  6970. result.defineAnnotatedConstants(RubyBigDecimal.class);
  6971. return result;
  6972. }
  6973. private boolean isNaN = false;
  6974. private int infinitySign = 0;
  6975. private int zeroSign = 0;
  6976. private BigDecimal value;
  6977. public BigDecimal getValue() {
  6978. return value;
  6979. }
  6980. public RubyBigDecimal(Ruby runtime, RubyClass klass) {
  6981. super(runtime, klass);
  6982. }
  6983. public RubyBigDecimal(Ruby runtime, BigDecimal value) {
  6984. super(runtime, runtime.fastGetClass("BigDecimal"));
  6985. this.value = value;
  6986. }
  6987. public static class BigDecimalKernelMethods {
  6988. @JRubyMethod(name = "BigDecimal", rest = true, module = true, visibility = Visibility.PRIVATE)
  6989. public static IRubyObject newBigDecimal(IRubyObject recv, IRubyObject[] args) {
  6990. return RubyBigDecimal.newBigDecimal(recv, args, Block.NULL_BLOCK);
  6991. }
  6992. }
  6993. public static RubyBigDecimal newBigDecimal(IRubyObject recv, IRubyObject[] args, Block unusedBlock) {
  6994. return newInstance(recv.getRuntime().fastGetClass("BigDecimal"), args);
  6995. }
  6996. @JRubyMethod(name = "ver", meta = true)
  6997. public static IRubyObject ver(IRubyObject recv) {
  6998. return recv.getRuntime().newString("1.0.1");
  6999. }
  7000. @JRubyMethod(name = "_dump", optional = 1, frame = true)
  7001. public IRubyObject dump(IRubyObject[] args, Block unusedBlock) {
  7002. RubyString precision = RubyString.newUnicodeString(args[0].getRuntime(), "0:");
  7003. RubyString str = this.asString();
  7004. return precision.append(str);
  7005. }
  7006. @JRubyMethod(name = "_load", required = 1, frame = true, meta = true)
  7007. public static RubyBigDecimal load(IRubyObject recv, IRubyObject from, Block block) {
  7008. RubyBigDecimal rubyBigDecimal = (RubyBigDecimal) (((RubyClass)recv).allocate());
  7009. String precisionAndValue = from.convertToString().asJavaString();
  7010. String value = precisionAndValue.substring(precisionAndValue.indexOf(":")+1);
  7011. rubyBigDecimal.value = new BigDecimal(value);
  7012. return rubyBigDecimal;
  7013. }
  7014. @JRubyMethod(name = "double_fig", meta = true)
  7015. public static IRubyObject double_fig(IRubyObject recv) {
  7016. return recv.getRuntime().newFixnum(20);
  7017. }
  7018. @JRubyMethod(name = "limit", optional = 1, meta = true)
  7019. public static IRubyObject limit(IRubyObject recv, IRubyObject[] args) {
  7020. Ruby runtime = recv.getRuntime();
  7021. RubyModule c = (RubyModule)recv;
  7022. IRubyObject nCur = c.searchInternalModuleVariable("vpPrecLimit");
  7023. if (args.length > 0) {
  7024. IRubyObject arg = args[0];
  7025. if (!arg.isNil()) {
  7026. if (!(arg instanceof RubyFixnum)) {
  7027. throw runtime.newTypeError(arg, runtime.getFixnum());
  7028. }
  7029. if (0 > ((RubyFixnum)arg).getLongValue()) {
  7030. throw runtime.newArgumentError("argument must be positive");
  7031. }
  7032. c.setInternalModuleVariable("vpPrecLimit", arg);
  7033. }
  7034. }
  7035. return nCur;
  7036. }
  7037. @JRubyMethod(name = "mode", required = 1, optional = 1, meta = true)
  7038. public static IRubyObject mode(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
  7039. // FIXME: I doubt any of the constants referenced in this method
  7040. // are ever redefined -- should compare to the known values, rather
  7041. // than do an expensive constant lookup.
  7042. Ruby runtime = recv.getRuntime();
  7043. RubyClass clazz = runtime.fastGetClass("BigDecimal");
  7044. RubyModule c = (RubyModule)recv;
  7045. args = Arity.scanArgs(runtime, args, 1, 1);
  7046. IRubyObject mode = args[0];
  7047. IRubyObject value = args[1];
  7048. if (!(mode instanceof RubyFixnum)) {
  7049. throw runtime.newTypeError("wrong argument type " + mode.getMetaClass() + " (expected Fixnum)");
  7050. }
  7051. long longMode = ((RubyFixnum)mode).getLongValue();
  7052. long EXCEPTION_ALL = ((RubyFixnum)clazz.fastGetConstant("EXCEPTION_ALL")).getLongValue();
  7053. if ((longMode & EXCEPTION_ALL) != 0) {
  7054. if (value.isNil()) {
  7055. return c.searchInternalModuleVariable("vpExceptionMode");
  7056. }
  7057. if (!(value.isNil()) && !(value instanceof RubyBoolean)) {
  7058. throw runtime.newTypeError("second argument must be true or false");
  7059. }
  7060. RubyFixnum currentExceptionMode = (RubyFixnum)c.searchInternalModuleVariable("vpExceptionMode");
  7061. RubyFixnum newExceptionMode = new RubyFixnum(runtime, currentExceptionMode.getLongValue());
  7062. RubyFixnum EXCEPTION_INFINITY = (RubyFixnum)clazz.fastGetConstant("EXCEPTION_INFINITY");
  7063. if ((longMode & EXCEPTION_INFINITY.getLongValue()) != 0) {
  7064. newExceptionMode = (value.isTrue()) ? (RubyFixnum)currentExceptionMode.callCoerced(context, "|", EXCEPTION_INFINITY)
  7065. : (RubyFixnum)currentExceptionMode.callCoerced(context, "&", new RubyFixnum(runtime, ~(EXCEPTION_INFINITY).getLongValue()));
  7066. }
  7067. RubyFixnum EXCEPTION_NaN = (RubyFixnum)clazz.fastGetConstant("EXCEPTION_NaN");
  7068. if ((longMode & EXCEPTION_NaN.getLongValue()) != 0) {
  7069. newExceptionMode = (value.isTrue()) ? (RubyFixnum)currentExceptionMode.callCoerced(context, "|", EXCEPTION_NaN)
  7070. : (RubyFixnum)currentExceptionMode.callCoerced(context, "&", new RubyFixnum(runtime, ~(EXCEPTION_NaN).getLongValue()));
  7071. }
  7072. c.setInternalModuleVariable("vpExceptionMode", newExceptionMode);
  7073. return newExceptionMode;
  7074. }
  7075. long ROUND_MODE = ((RubyFixnum)clazz.fastGetConstant("ROUND_MODE")).getLongValue();
  7076. if (longMode == ROUND_MODE) {
  7077. if (value.isNil()) {
  7078. return c.searchInternalModuleVariable("vpRoundingMode");
  7079. }
  7080. if (!(value instanceof RubyFixnum)) {
  7081. throw runtime.newTypeError("wrong argument type " + mode.getMetaClass() + " (expected Fixnum)");
  7082. }
  7083. RubyFixnum roundingMode = (RubyFixnum)value;
  7084. if (roundingMode == clazz.fastGetConstant("ROUND_UP") ||
  7085. roundingMode == clazz.fastGetConstant("ROUND_DOWN") ||
  7086. roundingMode == clazz.fastGetConstant("ROUND_FLOOR") ||
  7087. roundingMode == clazz.fastGetConstant("ROUND_CEILING") ||
  7088. roundingMode == clazz.fastGetConstant("ROUND_HALF_UP") ||
  7089. roundingMode == clazz.fastGetConstant("ROUND_HALF_DOWN") ||
  7090. roundingMode == clazz.fastGetConstant("ROUND_HALF_EVEN")) {
  7091. c.setInternalModuleVariable("vpRoundingMode", roundingMode);
  7092. } else {
  7093. throw runtime.newTypeError("invalid rounding mode");
  7094. }
  7095. return c.searchInternalModuleVariable("vpRoundingMode");
  7096. }
  7097. throw runtime.newTypeError("first argument for BigDecimal#mode invalid");
  7098. }
  7099. private RoundingMode getRoundingMode(Ruby runtime) {
  7100. RubyFixnum roundingMode = (RubyFixnum)runtime.fastGetClass("BigDecimal")
  7101. .searchInternalModuleVariable("vpRoundingMode");
  7102. return RoundingMode.valueOf((int)roundingMode.getLongValue());
  7103. }
  7104. private RubyBigDecimal getVpValue(IRubyObject v, boolean must) {
  7105. if(v instanceof RubyBigDecimal) {
  7106. return (RubyBigDecimal)v;
  7107. } else if(v instanceof RubyFixnum || v instanceof RubyBignum) {
  7108. String s = v.toString();
  7109. return newInstance(getRuntime().fastGetClass("BigDecimal"),new IRubyObject[]{getRuntime().newString(s)});
  7110. }
  7111. if(must) {
  7112. String err;
  7113. if (isImmediate()) {
  7114. ThreadContext context = getRuntime().getCurrentContext();
  7115. err = inspect(context, this).toString();
  7116. } else {
  7117. err = getMetaClass().getBaseName();
  7118. }
  7119. throw getRuntime().newTypeError(err + " can't be coerced into BigDecimal");
  7120. }
  7121. return null;
  7122. }
  7123. private final static Pattern INFINITY_PATTERN = Pattern.compile("^([+-])?Infinity$");
  7124. private final static Pattern NUMBER_PATTERN
  7125. = Pattern.compile("^([+-]?\\d*\\.?\\d*([eE][+-]?)?\\d*).*");
  7126. @JRubyMethod(name = "new", required = 1, optional = 1, meta = true)
  7127. public static RubyBigDecimal newInstance(IRubyObject recv, IRubyObject[] args) {
  7128. BigDecimal decimal;
  7129. if (args.length == 0) {
  7130. decimal = new BigDecimal(0);
  7131. } else {
  7132. String strValue = args[0].convertToString().toString();
  7133. strValue = strValue.trim();
  7134. if ("NaN".equals(strValue)) {
  7135. return newNaN(recv.getRuntime());
  7136. }
  7137. Matcher m = INFINITY_PATTERN.matcher(strValue);
  7138. if (m.matches()) {
  7139. int sign = 1;
  7140. String signGroup = m.group(1);
  7141. if ("-".equals(signGroup)) {
  7142. sign = -1;
  7143. }
  7144. return newInfinity(recv.getRuntime(), sign);
  7145. }
  7146. // Clean-up string representation so that it could be understood
  7147. // by Java's BigDecimal. Not terribly efficient for now.
  7148. // 1. MRI allows d and D as exponent separators
  7149. strValue = strValue.replaceFirst("[dD]", "E");
  7150. // 2. MRI allows underscores anywhere
  7151. strValue = strValue.replaceAll("_", "");
  7152. // 3. MRI ignores the trailing junk
  7153. strValue = NUMBER_PATTERN.matcher(strValue).replaceFirst("$1");
  7154. try {
  7155. decimal = new BigDecimal(strValue);
  7156. } catch(NumberFormatException e) {
  7157. decimal = new BigDecimal(0);
  7158. }
  7159. if (decimal.signum() == 0) {
  7160. // MRI behavior: -0 and +0 are two different things
  7161. if (strValue.matches("^\\s*-.*")) {
  7162. return newZero(recv.getRuntime(), -1);
  7163. } else {
  7164. return newZero(recv.getRuntime(), 1);
  7165. }
  7166. }
  7167. }
  7168. return new RubyBigDecimal(recv.getRuntime(), decimal);
  7169. }
  7170. private static RubyBigDecimal newZero(Ruby runtime, int sign) {
  7171. RubyBigDecimal rbd = new RubyBigDecimal(runtime, BigDecimal.ZERO);
  7172. if (sign < 0) {
  7173. rbd.zeroSign = -1;
  7174. } else {
  7175. rbd.zeroSign = 1;
  7176. }
  7177. return rbd;
  7178. }
  7179. private static RubyBigDecimal newNaN(Ruby runtime) {
  7180. RubyBigDecimal rbd = new RubyBigDecimal(runtime, BigDecimal.ZERO);
  7181. rbd.isNaN = true;
  7182. return rbd;
  7183. }
  7184. private static RubyBigDecimal newInfinity(Ruby runtime, int sign) {
  7185. RubyBigDecimal rbd = new RubyBigDecimal(runtime, BigDecimal.ZERO);
  7186. if (sign < 0) {
  7187. rbd.infinitySign = -1;
  7188. } else {
  7189. rbd.infinitySign = 1;
  7190. }
  7191. return rbd;
  7192. }
  7193. private RubyBigDecimal setResult() {
  7194. return setResult(0);
  7195. }
  7196. private RubyBigDecimal setResult(int scale) {
  7197. int prec = RubyFixnum.fix2int(getRuntime().fastGetClass("BigDecimal").searchInternalModuleVariable("vpPrecLimit"));
  7198. int prec2 = Math.max(scale,prec);
  7199. if(prec2 > 0 && this.value.scale() > (prec2-getExponent())) {
  7200. this.value = this.value.setScale(prec2-getExponent(),BigDecimal.ROUND_HALF_UP);
  7201. }
  7202. return this;
  7203. }
  7204. @JRubyMethod(name = "hash")
  7205. public RubyFixnum hash() {
  7206. return getRuntime().newFixnum(value.hashCode());
  7207. }
  7208. @JRubyMethod(name = {"%", "modulo"}, required = 1)
  7209. public IRubyObject op_mod(ThreadContext context, IRubyObject arg) {
  7210. // TODO: full-precision remainder is 1000x slower than MRI!
  7211. Ruby runtime = context.getRuntime();
  7212. if (isInfinity() || isNaN()) {
  7213. return newNaN(runtime);
  7214. }
  7215. RubyBigDecimal val = getVpValue(arg, false);
  7216. if (val == null) {
  7217. return callCoerced(context, "%", arg, true);
  7218. }
  7219. if (val.isInfinity() || val.isNaN() || val.isZero()) {
  7220. return newNaN(runtime);
  7221. }
  7222. // Java and MRI definitions of modulo are different.
  7223. BigDecimal modulo = value.remainder(val.value);
  7224. if (modulo.signum() * val.value.signum() < 0) {
  7225. modulo = modulo.add(val.value);
  7226. }
  7227. return new RubyBigDecimal(runtime, modulo).setResult();
  7228. }
  7229. @JRubyMethod(name = "remainder", required = 1)
  7230. public IRubyObject remainder(ThreadContext context, IRubyObject arg) {
  7231. // TODO: full-precision remainder is 1000x slower than MRI!
  7232. Ruby runtime = context.getRuntime();
  7233. if (isInfinity() || isNaN()) {
  7234. return newNaN(runtime);
  7235. }
  7236. RubyBigDecimal val = getVpValue(arg,false);
  7237. if (val == null) {
  7238. return callCoerced(context, "remainder", arg, true);
  7239. }
  7240. if (val.isInfinity() || val.isNaN() || val.isZero()) {
  7241. return newNaN(runtime);
  7242. }
  7243. // Java and MRI definitions of remainder are the same.
  7244. return new RubyBigDecimal(runtime, value.remainder(val.value)).setResult();
  7245. }
  7246. @JRubyMethod(name = "*", required = 1)
  7247. public IRubyObject op_mul(ThreadContext context, IRubyObject arg) {
  7248. return mult2(context, arg, RubyFixnum.zero(context.getRuntime()));
  7249. }
  7250. @JRubyMethod(name = "mult", required = 2)
  7251. public IRubyObject mult2(ThreadContext context, IRubyObject b, IRubyObject n) {
  7252. Ruby runtime = context.getRuntime();
  7253. RubyBigDecimal val = getVpValue(b,false);
  7254. if(val == null) {
  7255. // TODO: what about n arg?
  7256. return callCoerced(context, "*", b);
  7257. }
  7258. int digits = RubyNumeric.fix2int(n);
  7259. if (isNaN() || val.isNaN()) {
  7260. return newNaN(runtime);
  7261. }
  7262. if ((isInfinity() && val.isZero()) || (isZero() && val.isInfinity())) {
  7263. return newNaN(runtime);
  7264. }
  7265. if (isZero() || val.isZero()) {
  7266. int sign1 = isZero()? zeroSign : value.signum();
  7267. int sign2 = val.isZero() ? val.zeroSign : val.value.signum();
  7268. return newZero(runtime, sign1 * sign2);
  7269. }
  7270. if (isInfinity() || val.isInfinity()) {
  7271. int sign1 = isInfinity() ? infinitySign : value.signum();
  7272. int sign2 = val.isInfinity() ? val.infinitySign : val.value.signum();
  7273. return newInfinity(runtime, sign1 * sign2);
  7274. }
  7275. BigDecimal res = value.multiply(val.value);
  7276. if (res.precision() > digits) {
  7277. // TODO: rounding mode should not be hard-coded. See #mode.
  7278. res = res.round(new MathContext(digits, RoundingMode.HALF_UP));
  7279. }
  7280. return new RubyBigDecimal(runtime, res).setResult();
  7281. }
  7282. @JRubyMethod(name = {"**", "power"}, required = 1)
  7283. public IRubyObject op_pow(IRubyObject arg) {
  7284. if (!(arg instanceof RubyFixnum)) {
  7285. throw getRuntime().newTypeError("wrong argument type " + arg.getMetaClass() + " (expected Fixnum)");
  7286. }
  7287. if (isNaN() || isInfinity()) {
  7288. return newNaN(getRuntime());
  7289. }
  7290. int times = RubyNumeric.fix2int(arg.convertToInteger());
  7291. if (times < 0) {
  7292. if (isZero()) {
  7293. return newInfinity(getRuntime(), value.signum());
  7294. }
  7295. // Note: MRI has a very non-trivial way of calculating the precision,
  7296. // so we use very simple approximation here:
  7297. int precision = (-times + 4) * (getAllDigits().length() + 4);
  7298. return new RubyBigDecimal(getRuntime(),
  7299. value.pow(times, new MathContext(precision, RoundingMode.HALF_UP)));
  7300. } else {
  7301. return new RubyBigDecimal(getRuntime(), value.pow(times));
  7302. }
  7303. }
  7304. @JRubyMethod(name = "+", required = 1, frame=true)
  7305. public IRubyObject op_plus(ThreadContext context, IRubyObject b) {
  7306. return addInternal(context, b, "add", RubyFixnum.zero(context.getRuntime()));
  7307. }
  7308. @JRubyMethod(name = "add", required = 2, frame=true)
  7309. public IRubyObject add2(ThreadContext context, IRubyObject b, IRubyObject digits) {
  7310. return addInternal(context, b, "add", digits);
  7311. }
  7312. private IRubyObject addInternal(ThreadContext context, IRubyObject b, String op, IRubyObject digits) {
  7313. Ruby runtime = context.getRuntime();
  7314. int prec = getPositiveInt(context, digits);
  7315. RubyBigDecimal val = getVpValue(b, false);
  7316. if (val == null) {
  7317. // TODO:
  7318. // MRI behavior: Call "+" or "add", depending on the call.
  7319. // But this leads to exceptions when Floats are added. See:
  7320. // http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/17374
  7321. // return callCoerced(context, op, b, true); -- this is MRI behavior.
  7322. // We'll use ours for now, thus providing an ability to add Floats.
  7323. return callCoerced(context, "+", b, true);
  7324. }
  7325. IRubyObject res = handleAddSpecialValues(val);
  7326. if (res != null) {
  7327. return res;
  7328. }
  7329. RoundingMode roundMode = getRoundingMode(runtime);
  7330. return new RubyBigDecimal(runtime, value.add(
  7331. val.value, new MathContext(prec, roundMode))); // TODO: why this: .setResult();
  7332. }
  7333. private int getPositiveInt(ThreadContext context, IRubyObject arg) {
  7334. Ruby runtime = context.getRuntime();
  7335. if (arg instanceof RubyFixnum) {
  7336. int value = RubyNumeric.fix2int(arg);
  7337. if (value < 0) {
  7338. throw runtime.newArgumentError("argument must be positive");
  7339. }
  7340. return value;
  7341. } else {
  7342. throw runtime.newTypeError(arg, runtime.getFixnum());
  7343. }
  7344. }
  7345. private IRubyObject handleAddSpecialValues(RubyBigDecimal val) {
  7346. if (isNaN() || val.isNaN) {
  7347. return newNaN(getRuntime());
  7348. }
  7349. // TODO: don't calculate the same value 3 times
  7350. if (infinitySign * val.infinitySign > 0) {
  7351. return isInfinity() ? this : val;
  7352. }
  7353. if (infinitySign * val.infinitySign < 0) {
  7354. return newNaN(getRuntime());
  7355. }
  7356. if (infinitySign * val.infinitySign == 0) {
  7357. int sign = infinitySign + val.infinitySign;
  7358. if (sign != 0) {
  7359. return newInfinity(getRuntime(), sign);
  7360. }
  7361. }
  7362. return null;
  7363. }
  7364. @JRubyMethod(name = "+@")
  7365. public IRubyObject op_uplus() {
  7366. return this;
  7367. }
  7368. @JRubyMethod(name = "-", required = 1)
  7369. public IRubyObject op_minus(ThreadContext context, IRubyObject arg) {
  7370. RubyBigDecimal val = getVpValue(arg, false);
  7371. if(val == null) {
  7372. return callCoerced(context, "-", arg);
  7373. }
  7374. RubyBigDecimal res = handleMinusSpecialValues(val);
  7375. if (res != null) {
  7376. return res;
  7377. }
  7378. return new RubyBigDecimal(getRuntime(),value.subtract(val.value)).setResult();
  7379. }
  7380. @JRubyMethod(name = "sub", required = 2)
  7381. public IRubyObject sub2(ThreadContext context, IRubyObject b, IRubyObject n) {
  7382. RubyBigDecimal val = getVpValue(b, false);
  7383. if(val == null) {
  7384. return callCoerced(context, "-", b);
  7385. }
  7386. RubyBigDecimal res = handleMinusSpecialValues(val);
  7387. if (res != null) {
  7388. return res;
  7389. }
  7390. return new RubyBigDecimal(getRuntime(),value.subtract(val.value)).setResult();
  7391. }
  7392. private RubyBigDecimal handleMinusSpecialValues(RubyBigDecimal val) {
  7393. if (isNaN() || val.isNaN()) {
  7394. return newNaN(getRuntime());
  7395. }
  7396. // TODO: 3 times calculate the same value below
  7397. if (infinitySign * val.infinitySign > 0) {
  7398. return newNaN(getRuntime());
  7399. }
  7400. if (infinitySign * val.infinitySign < 0) {
  7401. return this;
  7402. }
  7403. if (infinitySign * val.infinitySign == 0) {
  7404. if (isInfinity()) {
  7405. return this;
  7406. }
  7407. if (val.isInfinity()) {
  7408. return newInfinity(getRuntime(), val.infinitySign * -1);
  7409. }
  7410. int sign = infinitySign + val.infinitySign;
  7411. if (sign != 0) {
  7412. return newInfinity(getRuntime(), sign);
  7413. }
  7414. }
  7415. return null;
  7416. }
  7417. @JRubyMethod(name = "-@")
  7418. public IRubyObject op_uminus() {
  7419. Ruby runtime = getRuntime();
  7420. if (isNaN()) {
  7421. return newNaN(runtime);
  7422. }
  7423. if (isInfinity()) {
  7424. return newInfinity(runtime, -infinitySign);
  7425. }
  7426. if (isZero()) {
  7427. return newZero(runtime, -zeroSign);
  7428. }
  7429. return new RubyBigDecimal(getRuntime(), value.negate());
  7430. }
  7431. @JRubyMethod(name = {"/", "quo"})
  7432. public IRubyObject op_quo(ThreadContext context, IRubyObject other) {
  7433. // regular division with some default precision
  7434. // TODO: proper algorithm to set the precision
  7435. return op_div(context, other, getRuntime().newFixnum(200));
  7436. }
  7437. @JRubyMethod(name = "div")
  7438. public IRubyObject op_div(ThreadContext context, IRubyObject other) {
  7439. // integer division
  7440. RubyBigDecimal val = getVpValue(other, false);
  7441. if (val == null) {
  7442. return callCoerced(context, "div", other);
  7443. }
  7444. if (isNaN() || val.isZero() || val.isNaN()) {
  7445. return newNaN(getRuntime());
  7446. }
  7447. if (isInfinity() || val.isInfinity()) {
  7448. return newNaN(getRuntime());
  7449. }
  7450. return new RubyBigDecimal(getRuntime(),
  7451. this.value.divideToIntegralValue(val.value)).setResult();
  7452. }
  7453. @JRubyMethod(name = "div")
  7454. public IRubyObject op_div(ThreadContext context, IRubyObject other, IRubyObject digits) {
  7455. // TODO: take BigDecimal.mode into account.
  7456. int scale = RubyNumeric.fix2int(digits);
  7457. RubyBigDecimal val = getVpValue(other, false);
  7458. if (val == null) {
  7459. return callCoerced(context, "/", other);
  7460. }
  7461. if (isNaN() || (isZero() && val.isZero()) || val.isNaN()) {
  7462. return newNaN(getRuntime());
  7463. }
  7464. if (val.isZero()) {
  7465. int sign1 = isInfinity() ? infinitySign : value.signum();
  7466. return newInfinity(getRuntime(), sign1 * val.zeroSign);
  7467. }
  7468. if (isInfinity() && !val.isInfinity()) {
  7469. return newInfinity(getRuntime(), infinitySign * val.value.signum());
  7470. }
  7471. if (!isInfinity() && val.isInfinity()) {
  7472. return newZero(getRuntime(), value.signum() * val.infinitySign);
  7473. }
  7474. if (isInfinity() && val.isInfinity()) {
  7475. return newNaN(getRuntime());
  7476. }
  7477. if (scale == 0) {
  7478. // MRI behavior: "If digits is 0, the result is the same as the / operator."
  7479. return op_quo(context, other);
  7480. } else {
  7481. // TODO: better algorithm to set precision needed
  7482. int prec = Math.max(200, scale);
  7483. return new RubyBigDecimal(getRuntime(),
  7484. value.divide(val.value, new MathContext(prec, RoundingMode.HALF_UP))).setResult(scale);
  7485. }
  7486. }
  7487. private IRubyObject cmp(ThreadContext context, IRubyObject r, char op) {
  7488. int e = 0;
  7489. RubyBigDecimal rb = getVpValue(r,false);
  7490. if(rb == null) {
  7491. IRubyObject ee = callCoerced(context, "<=>",r);
  7492. if(ee.isNil()) {
  7493. return getRuntime().getNil();
  7494. }
  7495. e = RubyNumeric.fix2int(ee);
  7496. } else {
  7497. if (isNaN() | rb.isNaN()) {
  7498. return getRuntime().getNil();
  7499. }
  7500. if (infinitySign != 0 || rb.infinitySign != 0) {
  7501. e = infinitySign - rb.infinitySign;
  7502. } else {
  7503. e = value.compareTo(rb.value);
  7504. }
  7505. }
  7506. switch(op) {
  7507. case '*': return getRuntime().newFixnum(e);
  7508. case '=': return (e==0)?getRuntime().getTrue():getRuntime().getFalse();
  7509. case '!': return (e!=0)?getRuntime().getTrue():getRuntime().getFalse();
  7510. case 'G': return (e>=0)?getRuntime().getTrue():getRuntime().getFalse();
  7511. case '>': return (e> 0)?getRuntime().getTrue():getRuntime().getFalse();
  7512. case 'L': return (e<=0)?getRuntime().getTrue():getRuntime().getFalse();
  7513. case '<': return (e< 0)?getRuntime().getTrue():getRuntime().getFalse();
  7514. }
  7515. return getRuntime().getNil();
  7516. }
  7517. @JRubyMethod(name = "<=>", required = 1)
  7518. public IRubyObject op_cmp(ThreadContext context, IRubyObject arg) {
  7519. return cmp(context, arg,'*');
  7520. }
  7521. @JRubyMethod(name = {"eql?", "==", "==="}, required = 1)
  7522. public IRubyObject eql_p(ThreadContext context, IRubyObject arg) {
  7523. return cmp(context, arg,'=');
  7524. }
  7525. @JRubyMethod(name = "<", required = 1)
  7526. public IRubyObject op_lt(ThreadContext context, IRubyObject arg) {
  7527. return cmp(context, arg,'<');
  7528. }
  7529. @JRubyMethod(name = "<=", required = 1)
  7530. public IRubyObject op_le(ThreadContext context, IRubyObject arg) {
  7531. return cmp(context, arg,'L');
  7532. }
  7533. @JRubyMethod(name = ">", required = 1)
  7534. public IRubyObject op_gt(ThreadContext context, IRubyObject arg) {
  7535. return cmp(context, arg,'>');
  7536. }
  7537. @JRubyMethod(name = ">=", required = 1)
  7538. public IRubyObject op_ge(ThreadContext context, IRubyObject arg) {
  7539. return cmp(context, arg,'G');
  7540. }
  7541. @JRubyMethod(name = "abs")
  7542. public IRubyObject abs() {
  7543. Ruby runtime = getRuntime();
  7544. if (isNaN) {
  7545. return newNaN(runtime);
  7546. }
  7547. if (isInfinity()) {
  7548. return newInfinity(runtime, 1);
  7549. }
  7550. return new RubyBigDecimal(getRuntime(), value.abs()).setResult();
  7551. }
  7552. @JRubyMethod(name = "ceil", optional = 1)
  7553. public IRubyObject ceil(IRubyObject[] args) {
  7554. if (isNaN) {
  7555. return newNaN(getRuntime());
  7556. }
  7557. if (isInfinity()) {
  7558. return newInfinity(getRuntime(), infinitySign);
  7559. }
  7560. int n = 0;
  7561. if (args.length > 0) {
  7562. n = RubyNumeric.fix2int(args[0]);
  7563. }
  7564. if (value.scale() > n) { // rounding neccessary
  7565. return new RubyBigDecimal(getRuntime(),
  7566. value.setScale(n, RoundingMode.CEILING));
  7567. } else {
  7568. return this;
  7569. }
  7570. }
  7571. @JRubyMethod(name = "coerce", required = 1)
  7572. public IRubyObject coerce(IRubyObject other) {
  7573. IRubyObject obj;
  7574. if(other instanceof RubyFloat) {
  7575. obj = getRuntime().newArray(other,to_f());
  7576. } else {
  7577. obj = getRuntime().newArray(getVpValue(other, true),this);
  7578. }
  7579. return obj;
  7580. }
  7581. public double getDoubleValue() { return value.doubleValue(); }
  7582. public long getLongValue() { return value.longValue(); }
  7583. public RubyNumeric multiplyWith(ThreadContext context, RubyInteger value) {
  7584. return (RubyNumeric)op_mul(context, value);
  7585. }
  7586. public RubyNumeric multiplyWith(ThreadContext context, RubyFloat value) {
  7587. return (RubyNumeric)op_mul(context, value);
  7588. }
  7589. public RubyNumeric multiplyWith(ThreadContext context, RubyBignum value) {
  7590. return (RubyNumeric)op_mul(context, value);
  7591. }
  7592. @JRubyMethod(name = "divmod", required = 1)
  7593. public IRubyObject divmod(ThreadContext context, IRubyObject other) {
  7594. // TODO: full-precision divmod is 1000x slower than MRI!
  7595. Ruby runtime = context.getRuntime();
  7596. if (isInfinity() || isNaN()) {
  7597. return RubyArray.newArray(runtime, newNaN(runtime), newNaN(runtime));
  7598. }
  7599. RubyBigDecimal val = getVpValue(other, false);
  7600. if (val == null) {
  7601. return callCoerced(context, "divmod", other, true);
  7602. }
  7603. if (val.isInfinity() || val.isNaN() || val.isZero()) {
  7604. return RubyArray.newArray(runtime, newNaN(runtime), newNaN(runtime));
  7605. }
  7606. // Java and MRI definitions of divmod are different.
  7607. BigDecimal[] divmod = value.divideAndRemainder(val.value);
  7608. BigDecimal div = divmod[0];
  7609. BigDecimal mod = divmod[1];
  7610. if (mod.signum() * val.value.signum() < 0) {
  7611. div = div.subtract(BigDecimal.ONE);
  7612. mod = mod.add(val.value);
  7613. }
  7614. return RubyArray.newArray(runtime,
  7615. new RubyBigDecimal(runtime, div),
  7616. new RubyBigDecimal(runtime, mod));
  7617. }
  7618. @JRubyMethod(name = "exponent")
  7619. public IRubyObject exponent() {
  7620. return getRuntime().newFixnum(getExponent());
  7621. }
  7622. @JRubyMethod(name = "finite?")
  7623. public IRubyObject finite_p() {
  7624. if (isNaN()) {
  7625. return getRuntime().getFalse();
  7626. }
  7627. return getRuntime().newBoolean(!isInfinity());
  7628. }
  7629. @JRubyMethod(name = "floor", optional = 1)
  7630. public IRubyObject floor(IRubyObject[]args) {
  7631. if (isNaN) {
  7632. return newNaN(getRuntime());
  7633. }
  7634. if (isInfinity()) {
  7635. return newInfinity(getRuntime(), infinitySign);
  7636. }
  7637. int n = 0;
  7638. if (args.length > 0) {
  7639. n = RubyNumeric.fix2int(args[0]);
  7640. }
  7641. if (value.scale() > n) { // rounding neccessary
  7642. return new RubyBigDecimal(getRuntime(),
  7643. value.setScale(n, RoundingMode.FLOOR));
  7644. } else {
  7645. return this;
  7646. }
  7647. }
  7648. @JRubyMethod(name = "frac")
  7649. public IRubyObject frac() {
  7650. if (isNaN) {
  7651. return newNaN(getRuntime());
  7652. }
  7653. if (isInfinity()) {
  7654. return newInfinity(getRuntime(), infinitySign);
  7655. }
  7656. if (value.scale() > 0 && value.precision() < value.scale()) {
  7657. return new RubyBigDecimal(getRuntime(), value);
  7658. }
  7659. BigDecimal val = value.subtract(((RubyBigDecimal)fix()).value);
  7660. return new RubyBigDecimal(getRuntime(), val);
  7661. }
  7662. @JRubyMethod(name = "infinite?")
  7663. public IRubyObject infinite_p() {
  7664. if (infinitySign == 0) {
  7665. return getRuntime().getNil();
  7666. }
  7667. return getRuntime().newFixnum(infinitySign);
  7668. }
  7669. @JRubyMethod(name = "inspect")
  7670. public IRubyObject inspect(ThreadContext context) {
  7671. StringBuilder val = new StringBuilder("#<BigDecimal:").append(Integer.toHexString(System.identityHashCode(this))).append(",");
  7672. val.append("'").append(this.callMethod(context, MethodIndex.TO_S, "to_s")).append("'").append(",");
  7673. val.append(getSignificantDigits().length()).append("(");
  7674. int len = getAllDigits().length();
  7675. int pow = len / 4;
  7676. val.append((pow + 1) * 4).append(")").append(">");
  7677. return getRuntime().newString(val.toString());
  7678. }
  7679. @JRubyMethod(name = "nan?")
  7680. public IRubyObject nan_p() {
  7681. return getRuntime().newBoolean(isNaN);
  7682. }
  7683. @JRubyMethod(name = "nonzero?")
  7684. public IRubyObject nonzero_p() {
  7685. return isZero() ? getRuntime().getNil() : this;
  7686. }
  7687. @JRubyMethod(name = "precs")
  7688. public IRubyObject precs() {
  7689. final Ruby runtime = getRuntime();
  7690. final IRubyObject[] array = new IRubyObject[2];
  7691. array[0] = runtime.newFixnum(getSignificantDigits().length());
  7692. int len = getAllDigits().length();
  7693. int pow = len / 4;
  7694. array[1] = runtime.newFixnum((pow + 1) * 4);
  7695. return RubyArray.newArray(runtime, array);
  7696. }
  7697. @JRubyMethod(name = "round", optional = 2)
  7698. public IRubyObject round(IRubyObject[] args) {
  7699. int scale = args.length > 0 ? num2int(args[0]) : 0;
  7700. int mode = (args.length > 1) ? javaRoundingModeFromRubyRoundingMode(args[1]) : BigDecimal.ROUND_HALF_UP;
  7701. // JRUBY-914: Java 1.4 BigDecimal does not allow a negative scale, so we have to simulate it
  7702. if (scale < 0) {
  7703. // shift the decimal point just to the right of the digit to be rounded to (divide by 10**(abs(scale)))
  7704. // -1 -> 10's digit, -2 -> 100's digit, etc.
  7705. BigDecimal normalized = value.movePointRight(scale);
  7706. // ...round to that digit
  7707. BigDecimal rounded = normalized.setScale(0,mode);
  7708. // ...and shift the result back to the left (multiply by 10**(abs(scale)))
  7709. return new RubyBigDecimal(getRuntime(), rounded.movePointLeft(scale));
  7710. } else {
  7711. return new RubyBigDecimal(getRuntime(), value.setScale(scale, mode));
  7712. }
  7713. }
  7714. //this relies on the Ruby rounding enumerations == Java ones, which they (currently) all are
  7715. private int javaRoundingModeFromRubyRoundingMode(IRubyObject arg) {
  7716. return num2int(arg);
  7717. }
  7718. @JRubyMethod(name = "sign")
  7719. public IRubyObject sign() {
  7720. if (isNaN()) {
  7721. return getMetaClass().fastGetConstant("SIGN_NaN");
  7722. }
  7723. if (isInfinity()) {
  7724. if (infinitySign < 0) {
  7725. return getMetaClass().fastGetConstant("SIGN_NEGATIVE_INFINITE");
  7726. } else {
  7727. return getMetaClass().fastGetConstant("SIGN_POSITIVE_INFINITE");
  7728. }
  7729. }
  7730. if (isZero()) {
  7731. if (zeroSign < 0) {
  7732. return getMetaClass().fastGetConstant("SIGN_NEGATIVE_ZERO");
  7733. } else {
  7734. return getMetaClass().fastGetConstant("SIGN_POSITIVE_ZERO");
  7735. }
  7736. }
  7737. if (value.signum() < 0) {
  7738. return getMetaClass().fastGetConstant("SIGN_NEGATIVE_FINITE");
  7739. } else {
  7740. return getMetaClass().fastGetConstant("SIGN_POSITIVE_FINITE");
  7741. }
  7742. }
  7743. @JRubyMethod(name = "split")
  7744. public RubyArray split() {
  7745. final Ruby runtime = getRuntime();
  7746. final IRubyObject[] array = new IRubyObject[4];
  7747. // sign
  7748. final RubyFixnum sign;
  7749. if (isNaN) {
  7750. sign = RubyFixnum.zero(runtime);
  7751. } else if (isInfinity()) {
  7752. sign = runtime.newFixnum(infinitySign);
  7753. } else if (isZero()){
  7754. sign = runtime.newFixnum(zeroSign);
  7755. } else {
  7756. sign = runtime.newFixnum(value.signum());
  7757. }
  7758. array[0] = sign;
  7759. // significant digits and exponent
  7760. final RubyString digits;
  7761. final RubyFixnum exp;
  7762. if (isNaN()) {
  7763. digits = runtime.newString("NaN");
  7764. exp = RubyFixnum.zero(runtime);
  7765. } else if (isInfinity()) {
  7766. digits = runtime.newString("Infinity");
  7767. exp = RubyFixnum.zero(runtime);
  7768. } else if (isZero()){
  7769. digits = runtime.newString("0");
  7770. exp = RubyFixnum.zero(runtime);
  7771. } else {
  7772. // normalize the value
  7773. digits = runtime.newString(getSignificantDigits());
  7774. exp = runtime.newFixnum(getExponent());
  7775. }
  7776. array[1] = digits;
  7777. array[3] = exp;
  7778. // base
  7779. array[2] = runtime.newFixnum(10);
  7780. return RubyArray.newArray(runtime, array);
  7781. }
  7782. // it doesn't handle special cases
  7783. private String getSignificantDigits() {
  7784. // TODO: no need to calculate every time.
  7785. BigDecimal val = value.abs().stripTrailingZeros();
  7786. return val.unscaledValue().toString();
  7787. }
  7788. private String getAllDigits() {
  7789. // TODO: no need to calculate every time.
  7790. BigDecimal val = value.abs();
  7791. return val.unscaledValue().toString();
  7792. }
  7793. // it doesn't handle special cases
  7794. private int getExponent() {
  7795. // TODO: no need to calculate every time.
  7796. if (isZero()) {
  7797. return 0;
  7798. }
  7799. BigDecimal val = value.abs().stripTrailingZeros();
  7800. return val.precision() - val.scale();
  7801. }
  7802. @JRubyMethod(name = "sqrt", required = 1)
  7803. public IRubyObject sqrt(IRubyObject arg) {
  7804. Ruby runtime = getRuntime();
  7805. if (isNaN()) {
  7806. throw runtime.newFloatDomainError("(VpSqrt) SQRT(NaN value)");
  7807. }
  7808. if ((isInfinity() && infinitySign < 0) || value.signum() < 0) {
  7809. throw runtime.newFloatDomainError("(VpSqrt) SQRT(negative value)");
  7810. }
  7811. if (isInfinity() && infinitySign > 0) {
  7812. return newInfinity(runtime, 1);
  7813. }
  7814. // NOTE: MRI's sqrt precision is limited by 100,
  7815. // but we allow values more than 100.
  7816. int n = RubyNumeric.fix2int(arg);
  7817. if (n < 0) {
  7818. throw runtime.newArgumentError("argument must be positive");
  7819. }
  7820. n += 4; // just in case, add a bit of extra precision
  7821. return new RubyBigDecimal(getRuntime(),
  7822. bigSqrt(this.value, new MathContext(n, RoundingMode.HALF_UP))).setResult();
  7823. }
  7824. @JRubyMethod(name = "to_f")
  7825. public IRubyObject to_f() {
  7826. if (isNaN()) {
  7827. return RubyFloat.newFloat(getRuntime(), Double.NaN);
  7828. }
  7829. if (isInfinity()) {
  7830. return RubyFloat.newFloat(getRuntime(),
  7831. infinitySign < 0 ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY);
  7832. }
  7833. if (isZero()) {
  7834. return RubyFloat.newFloat(getRuntime(),
  7835. zeroSign < 0 ? -0.0 : 0.0);
  7836. }
  7837. return RubyFloat.newFloat(getRuntime(), value.doubleValue());
  7838. }
  7839. @JRubyMethod(name = {"to_i", "to_int"})
  7840. public IRubyObject to_int() {
  7841. if (isNaN() || infinitySign != 0) {
  7842. return getRuntime().getNil();
  7843. }
  7844. try {
  7845. return RubyNumeric.int2fix(getRuntime(), value.longValueExact());
  7846. } catch (ArithmeticException ae) {
  7847. return RubyBignum.bignorm(getRuntime(), value.toBigInteger());
  7848. }
  7849. }
  7850. private String removeTrailingZeroes(String in) {
  7851. while(in.length() > 0 && in.charAt(in.length()-1)=='0') {
  7852. in = in.substring(0,in.length()-1);
  7853. }
  7854. return in;
  7855. }
  7856. public static boolean formatHasLeadingPlus(String format) {
  7857. return format.startsWith("+");
  7858. }
  7859. public static boolean formatHasLeadingSpace(String format) {
  7860. return format.startsWith(" ");
  7861. }
  7862. public static boolean formatHasFloatingPointNotation(String format) {
  7863. return format.endsWith("F");
  7864. }
  7865. public static int formatFractionalDigitGroups(String format) {
  7866. int groups = 0;
  7867. Pattern p = Pattern.compile("(\\+| )?(\\d+)(E|F)?");
  7868. Matcher m = p.matcher(format);
  7869. if (m.matches()) {
  7870. groups = Integer.parseInt(m.group(2));
  7871. }
  7872. return groups;
  7873. }
  7874. private boolean hasArg(IRubyObject[] args) {
  7875. return args.length != 0 && !args[0].isNil();
  7876. }
  7877. private String format(IRubyObject[] args) {
  7878. return args[0].toString();
  7879. }
  7880. private String firstArgument(IRubyObject[] args) {
  7881. if (hasArg(args)) {
  7882. return format(args);
  7883. }
  7884. return null;
  7885. }
  7886. private boolean posSpace(String arg) {
  7887. if (null != arg) {
  7888. return formatHasLeadingSpace(arg);
  7889. }
  7890. return false;
  7891. }
  7892. private boolean posSign(String arg) {
  7893. if (null != arg) {
  7894. return formatHasLeadingPlus(arg) || posSpace(arg);
  7895. }
  7896. return false;
  7897. }
  7898. private boolean asEngineering(String arg) {
  7899. if (null != arg) {
  7900. return !formatHasFloatingPointNotation(arg);
  7901. }
  7902. return true;
  7903. }
  7904. private int groups(String arg) {
  7905. if (null != arg) {
  7906. return formatFractionalDigitGroups(arg);
  7907. }
  7908. return 0;
  7909. }
  7910. private boolean isZero() {
  7911. return !isNaN() && !isInfinity() && (value.signum() == 0);
  7912. }
  7913. private boolean isNaN() {
  7914. return isNaN;
  7915. }
  7916. private boolean isInfinity() {
  7917. return infinitySign != 0;
  7918. }
  7919. private String unscaledValue() {
  7920. return value.abs().unscaledValue().toString();
  7921. }
  7922. private IRubyObject engineeringValue(String arg) {
  7923. int exponent = getExponent();
  7924. int signum = value.signum();
  7925. StringBuilder build = new StringBuilder();
  7926. build.append(signum == -1 ? "-" : (signum == 1 ? (posSign(arg) ? (posSpace(arg) ? " " : "+") : "") : ""));
  7927. build.append("0.");
  7928. if (0 == groups(arg)) {
  7929. String s = removeTrailingZeroes(unscaledValue());
  7930. if ("".equals(s)) {
  7931. build.append("0");
  7932. } else {
  7933. build.append(s);
  7934. }
  7935. } else {
  7936. int index = 0;
  7937. String sep = "";
  7938. while (index < unscaledValue().length()) {
  7939. int next = index + groups(arg);
  7940. if (next > unscaledValue().length()) {
  7941. next = unscaledValue().length();
  7942. }
  7943. build.append(sep).append(unscaledValue().substring(index, next));
  7944. sep = " ";
  7945. index += groups(arg);
  7946. }
  7947. }
  7948. build.append("E").append(exponent);
  7949. return getRuntime().newString(build.toString());
  7950. }
  7951. private IRubyObject floatingPointValue(String arg) {
  7952. String values[] = value.abs().stripTrailingZeros().toPlainString().split("\\.");
  7953. String whole = "0";
  7954. if (values.length > 0) {
  7955. whole = values[0];
  7956. }
  7957. String after = "0";
  7958. if (values.length > 1) {
  7959. after = values[1];
  7960. }
  7961. int signum = value.signum();
  7962. StringBuilder build = new StringBuilder();
  7963. build.append(signum == -1 ? "-" : (signum == 1 ? (posSign(arg) ? (posSpace(arg) ? " " : "+") : "") : ""));
  7964. if (groups(arg) == 0) {
  7965. build.append(whole);
  7966. if (null != after) {
  7967. build.append(".").append(after);
  7968. }
  7969. } else {
  7970. int index = 0;
  7971. String sep = "";
  7972. while (index < whole.length()) {
  7973. int next = index + groups(arg);
  7974. if (next > whole.length()) {
  7975. next = whole.length();
  7976. }
  7977. build.append(sep).append(whole.substring(index, next));
  7978. sep = " ";
  7979. index += groups(arg);
  7980. }
  7981. if (null != after) {
  7982. build.append(".");
  7983. index = 0;
  7984. sep = "";
  7985. while (index < after.length()) {
  7986. int next = index + groups(arg);
  7987. if (next > after.length()) {
  7988. next = after.length();
  7989. }
  7990. build.append(sep).append(after.substring(index, next));
  7991. sep = " ";
  7992. index += groups(arg);
  7993. }
  7994. }
  7995. }
  7996. return getRuntime().newString(build.toString());
  7997. }
  7998. @JRubyMethod(name = "to_s", optional = 1)
  7999. public IRubyObject to_s(IRubyObject[] args) {
  8000. String arg = firstArgument(args);
  8001. if (isNaN()) {
  8002. return getRuntime().newString("NaN");
  8003. }
  8004. if (infinitySign != 0) {
  8005. if (infinitySign == -1) {
  8006. return getRuntime().newString("-Infinity");
  8007. } else {
  8008. return getRuntime().newString("Infinity");
  8009. }
  8010. }
  8011. if (isZero()) {
  8012. String zero = "0.0";
  8013. if (zeroSign < 0) {
  8014. zero = "-" + zero;
  8015. }
  8016. return getRuntime().newString(zero);
  8017. }
  8018. if(asEngineering(arg)) {
  8019. return engineeringValue(arg);
  8020. } else {
  8021. return floatingPointValue(arg);
  8022. }
  8023. }
  8024. // Note: #fix has only no-arg form, but truncate allows optional parameter.
  8025. @JRubyMethod
  8026. public IRubyObject fix() {
  8027. return truncate(RubyFixnum.zero(getRuntime()));
  8028. }
  8029. @JRubyMethod
  8030. public IRubyObject truncate() {
  8031. return truncate(RubyFixnum.zero(getRuntime()));
  8032. }
  8033. @JRubyMethod
  8034. public IRubyObject truncate(IRubyObject arg) {
  8035. if (isNaN) {
  8036. return newNaN(getRuntime());
  8037. }
  8038. if (isInfinity()) {
  8039. return newInfinity(getRuntime(), infinitySign);
  8040. }
  8041. int n = RubyNumeric.fix2int(arg);
  8042. int precision = value.precision() - value.scale() + n;
  8043. if (precision > 0) {
  8044. return new RubyBigDecimal(getRuntime(),
  8045. value.round(new MathContext(precision, RoundingMode.DOWN)));
  8046. } else {
  8047. // TODO: proper sign
  8048. return new RubyBigDecimal(getRuntime(), BigDecimal.ZERO);
  8049. }
  8050. }
  8051. @JRubyMethod(name = "zero?")
  8052. public IRubyObject zero_p() {
  8053. return getRuntime().newBoolean(isZero());
  8054. }
  8055. /**
  8056. * Returns the correctly rounded square root of a positive
  8057. * BigDecimal. This method performs the fast <i>Square Root by
  8058. * Coupled Newton Iteration</i> algorithm by Timm Ahrendt, from
  8059. * the book "Pi, unleashed" by Jรถrg Arndt in a neat loop.
  8060. * <p>
  8061. * The code is based on Frans Lelieveld's code , used here with
  8062. * permission.
  8063. *
  8064. * @param squarD The number to get the root from.
  8065. * @param rootMC Precision and rounding mode.
  8066. * @return the root of the argument number
  8067. * @throws ArithmeticException
  8068. * if the argument number is negative
  8069. * @throws IllegalArgumentException
  8070. * if rootMC has precision 0
  8071. */
  8072. public static BigDecimal bigSqrt(BigDecimal squarD, MathContext rootMC) {
  8073. // General number and precision checking
  8074. int sign = squarD.signum();
  8075. if (sign == -1) {
  8076. throw new ArithmeticException("Square root of a negative number: " + squarD);
  8077. } else if(sign == 0) {
  8078. return squarD.round(rootMC);
  8079. }
  8080. int prec = rootMC.getPrecision(); // the requested precision
  8081. if (prec == 0) {
  8082. throw new IllegalArgumentException("Most roots won't have infinite precision = 0");
  8083. }
  8084. // Initial precision is that of double numbers 2^63/2 ~ 4E18
  8085. int BITS = 62; // 63-1 an even number of number bits
  8086. int nInit = 16; // precision seems 16 to 18 digits
  8087. MathContext nMC = new MathContext(18, RoundingMode.HALF_DOWN);
  8088. // Iteration variables, for the square root x and the reciprocal v
  8089. BigDecimal x = null, e = null; // initial x: x0 ~ sqrt()
  8090. BigDecimal v = null, g = null; // initial v: v0 = 1/(2*x)
  8091. // Estimate the square root with the foremost 62 bits of squarD
  8092. BigInteger bi = squarD.unscaledValue(); // bi and scale are a tandem
  8093. int biLen = bi.bitLength();
  8094. int shift = Math.max(0, biLen - BITS + (biLen%2 == 0 ? 0 : 1)); // even shift..
  8095. bi = bi.shiftRight(shift); // ..floors to 62 or 63 bit BigInteger
  8096. double root = Math.sqrt(bi.doubleValue());
  8097. BigDecimal halfBack = new BigDecimal(BigInteger.ONE.shiftLeft(shift/2));
  8098. int scale = squarD.scale();
  8099. if (scale % 2 == 1) {
  8100. root *= SQRT_10; // 5 -> 2, -5 -> -3 need half a scale more..
  8101. }
  8102. scale = (int) Math.floor(scale/2.); // ..where 100 -> 10 shifts the scale
  8103. // Initial x - use double root - multiply by halfBack to unshift - set new scale
  8104. x = new BigDecimal(root, nMC);
  8105. x = x.multiply(halfBack, nMC); // x0 ~ sqrt()
  8106. if (scale != 0) {
  8107. x = x.movePointLeft(scale);
  8108. }
  8109. if (prec < nInit) { // for prec 15 root x0 must surely be OK
  8110. return x.round(rootMC); // return small prec roots without iterations
  8111. }
  8112. // Initial v - the reciprocal
  8113. v = BigDecimal.ONE.divide(TWO.multiply(x), nMC); // v0 = 1/(2*x)
  8114. // Collect iteration precisions beforehand
  8115. List<Integer> nPrecs = new ArrayList<Integer>();
  8116. assert nInit > 3 : "Never ending loop!"; // assume nInit = 16 <= prec
  8117. // Let m be the exact digits precision in an earlier! loop
  8118. for (int m = prec + 1; m > nInit; m = m/2 + (m > 100 ? 1 : 2)) {
  8119. nPrecs.add(m);
  8120. }
  8121. // The loop of "Square Root by Coupled Newton Iteration"
  8122. for (int i = nPrecs.size() - 1; i > -1; i--) {
  8123. // Increase precision - next iteration supplies n exact digits
  8124. nMC = new MathContext(nPrecs.get(i), (i%2 == 1) ? RoundingMode.HALF_UP :
  8125. RoundingMode.HALF_DOWN);
  8126. // Next x // e = d - x^2
  8127. e = squarD.subtract(x.multiply(x, nMC), nMC);
  8128. if (i != 0) {
  8129. x = x.add(e.multiply(v, nMC)); // x += e*v ~ sqrt()
  8130. } else {
  8131. x = x.add(e.multiply(v, rootMC), rootMC); // root x is ready!
  8132. break;
  8133. }
  8134. // Next v // g = 1 - 2*x*v
  8135. g = BigDecimal.ONE.subtract(TWO.multiply(x).multiply(v, nMC));
  8136. v = v.add(g.multiply(v, nMC)); // v += g*v ~ 1/2/sqrt()
  8137. }
  8138. return x; // return sqrt(squarD) with precision of rootMC
  8139. }
  8140. }// RubyBigdecimal
  8141. /***** BEGIN LICENSE BLOCK *****
  8142. * Version: CPL 1.0/GPL 2.0/LGPL 2.1
  8143. *
  8144. * The contents of this file are subject to the Common Public
  8145. * License Version 1.0 (the "License"); you may not use this file
  8146. * except in compliance with the License. You may obtain a copy of
  8147. * the License at http://www.eclipse.org/legal/cpl-v10.html
  8148. *
  8149. * Software distributed under the License is distributed on an "AS
  8150. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  8151. * implied. See the License for the specific language governing
  8152. * rights and limitations under the License.
  8153. *
  8154. * Copyright (C) 2001 Alan Moore <alan_moore@gmx.net>
  8155. * Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
  8156. * Copyright (C) 2002 Benoit Cerrina <b.cerrina@wanadoo.fr>
  8157. * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
  8158. * Copyright (C) 2002-2004 Thomas E Enebo <enebo@acm.org>
  8159. * Copyright (C) 2004-2005 Charles O Nutter <headius@headius.com>
  8160. * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
  8161. *
  8162. * Alternatively, the contents of this file may be used under the terms of
  8163. * either of the GNU General Public License Version 2 or later (the "GPL"),
  8164. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  8165. * in which case the provisions of the GPL or the LGPL are applicable instead
  8166. * of those above. If you wish to allow use of your version of this file only
  8167. * under the terms of either the GPL or the LGPL, and not to allow others to
  8168. * use your version of this file under the terms of the CPL, indicate your
  8169. * decision by deleting the provisions above and replace them with the notice
  8170. * and other provisions required by the GPL or the LGPL. If you do not delete
  8171. * the provisions above, a recipient may use your version of this file under
  8172. * the terms of any one of the CPL, the GPL or the LGPL.
  8173. ***** END LICENSE BLOCK *****/
  8174. package org.jruby;
  8175. import java.io.IOException;
  8176. import java.math.BigDecimal;
  8177. import java.math.BigInteger;
  8178. import org.jruby.anno.JRubyClass;
  8179. import org.jruby.anno.JRubyMethod;
  8180. import org.jruby.common.IRubyWarnings.ID;
  8181. import org.jruby.runtime.ClassIndex;
  8182. import org.jruby.runtime.ObjectAllocator;
  8183. import org.jruby.runtime.ThreadContext;
  8184. import org.jruby.runtime.builtin.IRubyObject;
  8185. import org.jruby.runtime.marshal.MarshalStream;
  8186. import org.jruby.runtime.marshal.UnmarshalStream;
  8187. /**
  8188. *
  8189. * @author jpetersen
  8190. */
  8191. @JRubyClass(name="Bignum", parent="Integer")
  8192. public class RubyBignum extends RubyInteger {
  8193. public static RubyClass createBignumClass(Ruby runtime) {
  8194. RubyClass bignum = runtime.defineClass("Bignum", runtime.getInteger(),
  8195. ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);
  8196. runtime.setBignum(bignum);
  8197. bignum.index = ClassIndex.BIGNUM;
  8198. bignum.defineAnnotatedMethods(RubyBignum.class);
  8199. return bignum;
  8200. }
  8201. private static final int BIT_SIZE = 64;
  8202. private static final long MAX = (1L << (BIT_SIZE - 1)) - 1;
  8203. private static final BigInteger LONG_MAX = BigInteger.valueOf(MAX);
  8204. private static final BigInteger LONG_MIN = BigInteger.valueOf(-MAX - 1);
  8205. private final BigInteger value;
  8206. public RubyBignum(Ruby runtime, BigInteger value) {
  8207. super(runtime, runtime.getBignum());
  8208. this.value = value;
  8209. }
  8210. public int getNativeTypeIndex() {
  8211. return ClassIndex.BIGNUM;
  8212. }
  8213. public Class<?> getJavaClass() {
  8214. return BigInteger.class;
  8215. }
  8216. public static RubyBignum newBignum(Ruby runtime, long value) {
  8217. return newBignum(runtime, BigInteger.valueOf(value));
  8218. }
  8219. public static RubyBignum newBignum(Ruby runtime, double value) {
  8220. return newBignum(runtime, new BigDecimal(value).toBigInteger());
  8221. }
  8222. public static RubyBignum newBignum(Ruby runtime, BigInteger value) {
  8223. return new RubyBignum(runtime, value);
  8224. }
  8225. public static RubyBignum newBignum(Ruby runtime, String value) {
  8226. return new RubyBignum(runtime, new BigInteger(value));
  8227. }
  8228. public double getDoubleValue() {
  8229. return big2dbl(this);
  8230. }
  8231. public long getLongValue() {
  8232. return big2long(this);
  8233. }
  8234. /** Getter for property value.
  8235. * @return Value of property value.
  8236. */
  8237. public BigInteger getValue() {
  8238. return value;
  8239. }
  8240. /* ================
  8241. * Utility Methods
  8242. * ================
  8243. */
  8244. /* If the value will fit in a Fixnum, return one of those. */
  8245. /** rb_big_norm
  8246. *
  8247. */
  8248. public static RubyInteger bignorm(Ruby runtime, BigInteger bi) {
  8249. if (bi.compareTo(LONG_MIN) < 0 || bi.compareTo(LONG_MAX) > 0) {
  8250. return newBignum(runtime, bi);
  8251. }
  8252. return runtime.newFixnum(bi.longValue());
  8253. }
  8254. /** rb_big2long
  8255. *
  8256. */
  8257. public static long big2long(RubyBignum value) {
  8258. BigInteger big = value.getValue();
  8259. if (big.compareTo(LONG_MIN) < 0 || big.compareTo(LONG_MAX) > 0) {
  8260. throw value.getRuntime().newRangeError("bignum too big to convert into `long'");
  8261. }
  8262. return big.longValue();
  8263. }
  8264. /** rb_big2dbl
  8265. *
  8266. */
  8267. public static double big2dbl(RubyBignum value) {
  8268. BigInteger big = value.getValue();
  8269. double dbl = convertToDouble(big);
  8270. if (dbl == Double.NEGATIVE_INFINITY || dbl == Double.POSITIVE_INFINITY) {
  8271. value.getRuntime().getWarnings().warn(ID.BIGNUM_FROM_FLOAT_RANGE, "Bignum out of Float range");
  8272. }
  8273. return dbl;
  8274. }
  8275. private IRubyObject checkShiftDown(RubyBignum other) {
  8276. if (other.value.signum() == 0) return RubyFixnum.zero(getRuntime());
  8277. if (value.compareTo(LONG_MIN) < 0 || value.compareTo(LONG_MAX) > 0) {
  8278. return other.value.signum() >= 0 ? RubyFixnum.zero(getRuntime()) : RubyFixnum.minus_one(getRuntime());
  8279. }
  8280. return getRuntime().getNil();
  8281. }
  8282. /**
  8283. * BigInteger#doubleValue is _really_ slow currently.
  8284. * This is faster, and mostly correct (?)
  8285. */
  8286. static double convertToDouble(BigInteger bigint) {
  8287. byte[] arr = bigint.toByteArray();
  8288. double res = 0;
  8289. double acc = 1;
  8290. for (int i = arr.length - 1; i > 0 ; i--)
  8291. {
  8292. res += (double) (arr[i] & 0xff) * acc;
  8293. acc *= 256;
  8294. }
  8295. res += (double) arr[0] * acc; // final byte sign is significant
  8296. return res;
  8297. }
  8298. /** rb_int2big
  8299. *
  8300. */
  8301. public static BigInteger fix2big(RubyFixnum arg) {
  8302. return BigInteger.valueOf(arg.getLongValue());
  8303. }
  8304. /* ================
  8305. * Instance Methods
  8306. * ================
  8307. */
  8308. /** rb_big_to_s
  8309. *
  8310. */
  8311. @JRubyMethod(name = "to_s", optional = 1)
  8312. public IRubyObject to_s(IRubyObject[] args) {
  8313. int base = args.length == 0 ? 10 : num2int(args[0]);
  8314. if (base < 2 || base > 36) {
  8315. throw getRuntime().newArgumentError("illegal radix " + base);
  8316. }
  8317. return getRuntime().newString(getValue().toString(base));
  8318. }
  8319. /** rb_big_coerce
  8320. *
  8321. */
  8322. @JRubyMethod(name = "coerce", required = 1)
  8323. public IRubyObject coerce(IRubyObject other) {
  8324. if (other instanceof RubyFixnum) {
  8325. return getRuntime().newArray(newBignum(getRuntime(), ((RubyFixnum) other).getLongValue()), this);
  8326. } else if (other instanceof RubyBignum) {
  8327. return getRuntime().newArray(newBignum(getRuntime(), ((RubyBignum) other).getValue()), this);
  8328. }
  8329. throw getRuntime().newTypeError("Can't coerce " + other.getMetaClass().getName() + " to Bignum");
  8330. }
  8331. /** rb_big_uminus
  8332. *
  8333. */
  8334. @JRubyMethod(name = "-@")
  8335. public IRubyObject op_uminus() {
  8336. return bignorm(getRuntime(), value.negate());
  8337. }
  8338. /** rb_big_plus
  8339. *
  8340. */
  8341. @JRubyMethod(name = "+", required = 1)
  8342. public IRubyObject op_plus(ThreadContext context, IRubyObject other) {
  8343. if (other instanceof RubyFixnum) {
  8344. return addFixnum((RubyFixnum)other);
  8345. } else if (other instanceof RubyBignum) {
  8346. return addBignum((RubyBignum)other);
  8347. } else if (other instanceof RubyFloat) {
  8348. return addFloat((RubyFloat)other);
  8349. }
  8350. return addOther(context, other);
  8351. }
  8352. private IRubyObject addFixnum(RubyFixnum other) {
  8353. return bignorm(getRuntime(), value.add(fix2big(other)));
  8354. }
  8355. private IRubyObject addBignum(RubyBignum other) {
  8356. return bignorm(getRuntime(), value.add(other.value));
  8357. }
  8358. private IRubyObject addFloat(RubyFloat other) {
  8359. return RubyFloat.newFloat(getRuntime(), big2dbl(this) + other.getDoubleValue());
  8360. }
  8361. private IRubyObject addOther(ThreadContext context, IRubyObject other) {
  8362. return coerceBin(context, "+", other);
  8363. }
  8364. /** rb_big_minus
  8365. *
  8366. */
  8367. @JRubyMethod(name = "-", required = 1)
  8368. public IRubyObject op_minus(ThreadContext context, IRubyObject other) {
  8369. if (other instanceof RubyFixnum) {
  8370. return subtractFixnum((RubyFixnum)other);
  8371. } else if (other instanceof RubyBignum) {
  8372. return subtractBignum((RubyBignum)other);
  8373. } else if (other instanceof RubyFloat) {
  8374. return subtractFloat((RubyFloat)other);
  8375. }
  8376. return subtractOther(context, other);
  8377. }
  8378. private IRubyObject subtractFixnum(RubyFixnum other) {
  8379. return bignorm(getRuntime(), value.subtract(fix2big(((RubyFixnum) other))));
  8380. }
  8381. private IRubyObject subtractBignum(RubyBignum other) {
  8382. return bignorm(getRuntime(), value.subtract(((RubyBignum) other).value));
  8383. }
  8384. private IRubyObject subtractFloat(RubyFloat other) {
  8385. return RubyFloat.newFloat(getRuntime(), big2dbl(this) - ((RubyFloat) other).getDoubleValue());
  8386. }
  8387. private IRubyObject subtractOther(ThreadContext context, IRubyObject other) {
  8388. return coerceBin(context, "-", other);
  8389. }
  8390. /** rb_big_mul
  8391. *
  8392. */
  8393. @JRubyMethod(name = "*", required = 1)
  8394. public IRubyObject op_mul(ThreadContext context, IRubyObject other) {
  8395. if (other instanceof RubyFixnum) {
  8396. return bignorm(getRuntime(), value.multiply(fix2big(((RubyFixnum) other))));
  8397. }
  8398. if (other instanceof RubyBignum) {
  8399. return bignorm(getRuntime(), value.multiply(((RubyBignum) other).value));
  8400. } else if (other instanceof RubyFloat) {
  8401. return RubyFloat.newFloat(getRuntime(), big2dbl(this) * ((RubyFloat) other).getDoubleValue());
  8402. }
  8403. return coerceBin(context, "*", other);
  8404. }
  8405. /**
  8406. * rb_big_divide. Shared part for both "/" and "div" operations.
  8407. */
  8408. private IRubyObject op_divide(ThreadContext context, IRubyObject other, String op) {
  8409. assert ("/".equals(op) || "div".equals(op));
  8410. final BigInteger otherValue;
  8411. if (other instanceof RubyFixnum) {
  8412. otherValue = fix2big((RubyFixnum) other);
  8413. } else if (other instanceof RubyBignum) {
  8414. otherValue = ((RubyBignum) other).value;
  8415. } else if (other instanceof RubyFloat) {
  8416. double div = big2dbl(this) / ((RubyFloat) other).getDoubleValue();
  8417. if ("/".equals(op)) {
  8418. return RubyFloat.newFloat(getRuntime(),
  8419. big2dbl(this) / ((RubyFloat) other).getDoubleValue());
  8420. } else {
  8421. return RubyNumeric.dbl2num(getRuntime(), div);
  8422. }
  8423. } else {
  8424. return coerceBin(context, op, other);
  8425. }
  8426. if (otherValue.equals(BigInteger.ZERO)) {
  8427. throw getRuntime().newZeroDivisionError();
  8428. }
  8429. BigInteger[] results = value.divideAndRemainder(otherValue);
  8430. if ((value.signum() * otherValue.signum()) == -1 && results[1].signum() != 0) {
  8431. return bignorm(getRuntime(), results[0].subtract(BigInteger.ONE));
  8432. }
  8433. return bignorm(getRuntime(), results[0]);
  8434. }
  8435. /** rb_big_div
  8436. *
  8437. */
  8438. @JRubyMethod(name = {"/"}, required = 1)
  8439. public IRubyObject op_div(ThreadContext context, IRubyObject other) {
  8440. return op_divide(context, other, "/");
  8441. }
  8442. /** rb_big_idiv
  8443. *
  8444. */
  8445. @JRubyMethod(name = {"div"}, required = 1)
  8446. public IRubyObject op_idiv(ThreadContext context, IRubyObject other) {
  8447. return op_divide(context, other, "div");
  8448. }
  8449. /** rb_big_divmod
  8450. *
  8451. */
  8452. @JRubyMethod(name = "divmod", required = 1)
  8453. public IRubyObject divmod(ThreadContext context, IRubyObject other) {
  8454. final BigInteger otherValue;
  8455. if (other instanceof RubyFixnum) {
  8456. otherValue = fix2big((RubyFixnum) other);
  8457. } else if (other instanceof RubyBignum) {
  8458. otherValue = ((RubyBignum) other).value;
  8459. } else {
  8460. return coerceBin(context, "divmod", other);
  8461. }
  8462. if (otherValue.equals(BigInteger.ZERO)) {
  8463. throw getRuntime().newZeroDivisionError();
  8464. }
  8465. BigInteger[] results = value.divideAndRemainder(otherValue);
  8466. if ((value.signum() * otherValue.signum()) == -1 && results[1].signum() != 0) {
  8467. results[0] = results[0].subtract(BigInteger.ONE);
  8468. results[1] = otherValue.add(results[1]);
  8469. }
  8470. final Ruby runtime = getRuntime();
  8471. return RubyArray.newArray(getRuntime(), bignorm(runtime, results[0]), bignorm(runtime, results[1]));
  8472. }
  8473. /** rb_big_modulo
  8474. *
  8475. */
  8476. @JRubyMethod(name = {"%", "modulo"}, required = 1)
  8477. public IRubyObject op_mod(ThreadContext context, IRubyObject other) {
  8478. final BigInteger otherValue;
  8479. if (other instanceof RubyFixnum) {
  8480. otherValue = fix2big((RubyFixnum) other);
  8481. } else if (other instanceof RubyBignum) {
  8482. otherValue = ((RubyBignum) other).value;
  8483. } else {
  8484. return coerceBin(context, "%", other);
  8485. }
  8486. if (otherValue.equals(BigInteger.ZERO)) {
  8487. throw getRuntime().newZeroDivisionError();
  8488. }
  8489. BigInteger result = value.mod(otherValue.abs());
  8490. if (otherValue.signum() == -1 && result.signum() != 0) {
  8491. result = otherValue.add(result);
  8492. }
  8493. return bignorm(getRuntime(), result);
  8494. }
  8495. /** rb_big_remainder
  8496. *
  8497. */
  8498. @JRubyMethod(name = "remainder", required = 1)
  8499. public IRubyObject remainder(ThreadContext context, IRubyObject other) {
  8500. final BigInteger otherValue;
  8501. if (other instanceof RubyFixnum) {
  8502. otherValue = fix2big(((RubyFixnum) other));
  8503. } else if (other instanceof RubyBignum) {
  8504. otherValue = ((RubyBignum) other).value;
  8505. } else {
  8506. return coerceBin(context, "remainder", other);
  8507. }
  8508. if (otherValue.equals(BigInteger.ZERO)) {
  8509. throw getRuntime().newZeroDivisionError();
  8510. }
  8511. return bignorm(getRuntime(), value.remainder(otherValue));
  8512. }
  8513. /** rb_big_quo
  8514. *
  8515. */
  8516. @JRubyMethod(name = "quo", required = 1)
  8517. public IRubyObject quo(ThreadContext context, IRubyObject other) {
  8518. if (other instanceof RubyNumeric) {
  8519. return RubyFloat.newFloat(getRuntime(), big2dbl(this) / ((RubyNumeric) other).getDoubleValue());
  8520. } else {
  8521. return coerceBin(context, "quo", other);
  8522. }
  8523. }
  8524. /** rb_big_pow
  8525. *
  8526. */
  8527. @JRubyMethod(name = {"**", "power"}, required = 1)
  8528. public IRubyObject op_pow(ThreadContext context, IRubyObject other) {
  8529. double d;
  8530. if (other instanceof RubyFixnum) {
  8531. RubyFixnum fix = (RubyFixnum) other;
  8532. long fixValue = fix.getLongValue();
  8533. // MRI issuses warning here on (RBIGNUM(x)->len * SIZEOF_BDIGITS * yy > 1024*1024)
  8534. if (((value.bitLength() + 7) / 8) * 4 * Math.abs(fixValue) > 1024 * 1024) {
  8535. getRuntime().getWarnings().warn(ID.MAY_BE_TOO_BIG, "in a**b, b may be too big", fixValue);
  8536. }
  8537. if (fixValue >= 0) {
  8538. return bignorm(getRuntime(), value.pow((int) fixValue)); // num2int is also implemented
  8539. } else {
  8540. return RubyFloat.newFloat(getRuntime(), Math.pow(big2dbl(this), (double)fixValue));
  8541. }
  8542. } else if (other instanceof RubyBignum) {
  8543. d = ((RubyBignum) other).getDoubleValue();
  8544. getRuntime().getWarnings().warn(ID.MAY_BE_TOO_BIG, "in a**b, b may be too big", d);
  8545. } else if (other instanceof RubyFloat) {
  8546. d = ((RubyFloat) other).getDoubleValue();
  8547. } else {
  8548. return coerceBin(context, "**", other);
  8549. }
  8550. return RubyFloat.newFloat(getRuntime(), Math.pow(big2dbl(this), d));
  8551. }
  8552. /** rb_big_pow
  8553. *
  8554. */
  8555. @JRubyMethod(name = {"**", "power"}, required = 1, compat = CompatVersion.RUBY1_9)
  8556. public IRubyObject op_pow_19(ThreadContext context, IRubyObject other) {
  8557. Ruby runtime = context.getRuntime();
  8558. if (other == RubyFixnum.zero(runtime)) return RubyFixnum.one(runtime);
  8559. double d;
  8560. if (other instanceof RubyFixnum) {
  8561. RubyFixnum fix = (RubyFixnum) other;
  8562. long fixValue = fix.getLongValue();
  8563. if (fixValue < 0) {
  8564. return RubyRational.newRationalRaw(runtime, this).callMethod(context, "**", other);
  8565. }
  8566. // MRI issuses warning here on (RBIGNUM(x)->len * SIZEOF_BDIGITS * yy > 1024*1024)
  8567. if (((value.bitLength() + 7) / 8) * 4 * Math.abs(fixValue) > 1024 * 1024) {
  8568. getRuntime().getWarnings().warn(ID.MAY_BE_TOO_BIG, "in a**b, b may be too big", fixValue);
  8569. }
  8570. if (fixValue >= 0) {
  8571. return bignorm(runtime, value.pow((int) fixValue)); // num2int is also implemented
  8572. } else {
  8573. return RubyFloat.newFloat(runtime, Math.pow(big2dbl(this), (double)fixValue));
  8574. }
  8575. } else if (other instanceof RubyBignum) {
  8576. if (other.callMethod(context, "<", RubyFixnum.zero(runtime)).isTrue()) {
  8577. return RubyRational.newRationalRaw(runtime, this).callMethod(context, "**", other);
  8578. }
  8579. d = ((RubyBignum) other).getDoubleValue();
  8580. getRuntime().getWarnings().warn(ID.MAY_BE_TOO_BIG, "in a**b, b may be too big", d);
  8581. } else if (other instanceof RubyFloat) {
  8582. d = ((RubyFloat) other).getDoubleValue();
  8583. } else {
  8584. return coerceBin(context, "**", other);
  8585. }
  8586. return RubyNumeric.dbl2num(runtime, Math.pow(big2dbl(this), d));
  8587. }
  8588. /** rb_big_and
  8589. *
  8590. */
  8591. @JRubyMethod(name = "&", required = 1)
  8592. public IRubyObject op_and(ThreadContext context, IRubyObject other) {
  8593. other = other.convertToInteger();
  8594. if (other instanceof RubyBignum) {
  8595. return bignorm(getRuntime(), value.and(((RubyBignum) other).value));
  8596. } else if(other instanceof RubyFixnum) {
  8597. return bignorm(getRuntime(), value.and(fix2big((RubyFixnum)other)));
  8598. }
  8599. return coerceBin(context, "&", other);
  8600. }
  8601. /** rb_big_or
  8602. *
  8603. */
  8604. @JRubyMethod(name = "|", required = 1)
  8605. public IRubyObject op_or(ThreadContext context, IRubyObject other) {
  8606. other = other.convertToInteger();
  8607. if (other instanceof RubyBignum) {
  8608. return bignorm(getRuntime(), value.or(((RubyBignum) other).value));
  8609. }
  8610. if (other instanceof RubyFixnum) { // no bignorm here needed
  8611. return bignorm(getRuntime(), value.or(fix2big((RubyFixnum)other)));
  8612. }
  8613. return coerceBin(context, "|", other);
  8614. }
  8615. /** rb_big_xor
  8616. *
  8617. */
  8618. @JRubyMethod(name = "^", required = 1)
  8619. public IRubyObject op_xor(ThreadContext context, IRubyObject other) {
  8620. other = other.convertToInteger();
  8621. if (other instanceof RubyBignum) {
  8622. return bignorm(getRuntime(), value.xor(((RubyBignum) other).value));
  8623. }
  8624. if (other instanceof RubyFixnum) {
  8625. return bignorm(getRuntime(), value.xor(BigInteger.valueOf(((RubyFixnum) other).getLongValue())));
  8626. }
  8627. return coerceBin(context, "^", other);
  8628. }
  8629. /** rb_big_neg
  8630. *
  8631. */
  8632. @JRubyMethod(name = "~")
  8633. public IRubyObject op_neg() {
  8634. return RubyBignum.newBignum(getRuntime(), value.not());
  8635. }
  8636. /** rb_big_lshift
  8637. *
  8638. */
  8639. @JRubyMethod(name = "<<", required = 1)
  8640. public IRubyObject op_lshift(IRubyObject other) {
  8641. long shift;
  8642. boolean neg = false;
  8643. for (;;) {
  8644. if (other instanceof RubyFixnum) {
  8645. shift = ((RubyFixnum)other).getLongValue();
  8646. if (shift < 0) {
  8647. neg = true;
  8648. shift = -shift;
  8649. }
  8650. break;
  8651. } else if (other instanceof RubyBignum) {
  8652. RubyBignum otherBignum = (RubyBignum)other;
  8653. if (otherBignum.value.signum() < 0) {
  8654. IRubyObject tmp = otherBignum.checkShiftDown(this);
  8655. if (!tmp.isNil()) return tmp;
  8656. neg = true;
  8657. }
  8658. shift = big2long(otherBignum);
  8659. break;
  8660. }
  8661. other = other.convertToInteger();
  8662. }
  8663. return bignorm(getRuntime(), neg ? value.shiftRight((int)shift) : value.shiftLeft((int)shift));
  8664. }
  8665. /** rb_big_rshift
  8666. *
  8667. */
  8668. @JRubyMethod(name = ">>", required = 1)
  8669. public IRubyObject op_rshift(IRubyObject other) {
  8670. long shift;
  8671. boolean neg = false;
  8672. for (;;) {
  8673. if (other instanceof RubyFixnum) {
  8674. shift = ((RubyFixnum)other).getLongValue();
  8675. if (shift < 0) {
  8676. neg = true;
  8677. shift = -shift;
  8678. }
  8679. break;
  8680. } else if (other instanceof RubyBignum) {
  8681. RubyBignum otherBignum = (RubyBignum)other;
  8682. if (otherBignum.value.signum() >= 0) {
  8683. IRubyObject tmp = otherBignum.checkShiftDown(this);
  8684. if (!tmp.isNil()) return tmp;
  8685. } else {
  8686. neg = true;
  8687. }
  8688. shift = big2long(otherBignum);
  8689. break;
  8690. }
  8691. other = other.convertToInteger();
  8692. }
  8693. return bignorm(getRuntime(), neg ? value.shiftLeft((int)shift) : value.shiftRight((int)shift));
  8694. }
  8695. /** rb_big_aref
  8696. *
  8697. */
  8698. @JRubyMethod(name = "[]", required = 1)
  8699. public RubyFixnum op_aref(IRubyObject other) {
  8700. if (other instanceof RubyBignum) {
  8701. if (((RubyBignum) other).value.signum() >= 0 || value.signum() == -1) {
  8702. return RubyFixnum.zero(getRuntime());
  8703. }
  8704. return RubyFixnum.one(getRuntime());
  8705. }
  8706. long position = num2long(other);
  8707. if (position < 0 || position > Integer.MAX_VALUE) {
  8708. return RubyFixnum.zero(getRuntime());
  8709. }
  8710. return value.testBit((int)position) ? RubyFixnum.one(getRuntime()) : RubyFixnum.zero(getRuntime());
  8711. }
  8712. /** rb_big_cmp
  8713. *
  8714. */
  8715. @JRubyMethod(name = "<=>", required = 1)
  8716. public IRubyObject op_cmp(ThreadContext context, IRubyObject other) {
  8717. final BigInteger otherValue;
  8718. if (other instanceof RubyFixnum) {
  8719. otherValue = fix2big((RubyFixnum) other);
  8720. } else if (other instanceof RubyBignum) {
  8721. otherValue = ((RubyBignum) other).value;
  8722. } else if (other instanceof RubyFloat) {
  8723. return dbl_cmp(getRuntime(), big2dbl(this), ((RubyFloat) other).getDoubleValue());
  8724. } else {
  8725. return coerceCmp(context, "<=>", other);
  8726. }
  8727. // wow, the only time we can use the java protocol ;)
  8728. return RubyFixnum.newFixnum(getRuntime(), value.compareTo(otherValue));
  8729. }
  8730. /** rb_big_eq
  8731. *
  8732. */
  8733. @JRubyMethod(name = "==", required = 1)
  8734. public IRubyObject op_equal(IRubyObject other) {
  8735. final BigInteger otherValue;
  8736. if (other instanceof RubyFixnum) {
  8737. otherValue = fix2big((RubyFixnum) other);
  8738. } else if (other instanceof RubyBignum) {
  8739. otherValue = ((RubyBignum) other).value;
  8740. } else if (other instanceof RubyFloat) {
  8741. double a = ((RubyFloat) other).getDoubleValue();
  8742. if (Double.isNaN(a)) {
  8743. return getRuntime().getFalse();
  8744. }
  8745. return RubyBoolean.newBoolean(getRuntime(), a == big2dbl(this));
  8746. } else {
  8747. return other.op_eqq(getRuntime().getCurrentContext(), this);
  8748. }
  8749. return RubyBoolean.newBoolean(getRuntime(), value.compareTo(otherValue) == 0);
  8750. }
  8751. /** rb_big_eql
  8752. *
  8753. */
  8754. @JRubyMethod(name = {"eql?", "==="}, required = 1)
  8755. public IRubyObject eql_p(IRubyObject other) {
  8756. if (other instanceof RubyBignum) {
  8757. return value.compareTo(((RubyBignum)other).value) == 0 ? getRuntime().getTrue() : getRuntime().getFalse();
  8758. }
  8759. return getRuntime().getFalse();
  8760. }
  8761. /** rb_big_hash
  8762. *
  8763. */
  8764. @JRubyMethod(name = "hash")
  8765. public RubyFixnum hash() {
  8766. return getRuntime().newFixnum(value.hashCode());
  8767. }
  8768. /** rb_big_to_f
  8769. *
  8770. */
  8771. @JRubyMethod(name = "to_f")
  8772. public IRubyObject to_f() {
  8773. return RubyFloat.newFloat(getRuntime(), getDoubleValue());
  8774. }
  8775. /** rb_big_abs
  8776. *
  8777. */
  8778. @JRubyMethod(name = "abs")
  8779. public IRubyObject abs() {
  8780. return RubyBignum.newBignum(getRuntime(), value.abs());
  8781. }
  8782. /** rb_big_size
  8783. *
  8784. */
  8785. @JRubyMethod(name = "size")
  8786. public IRubyObject size() {
  8787. return getRuntime().newFixnum((value.bitLength() + 7) / 8);
  8788. }
  8789. public static void marshalTo(RubyBignum bignum, MarshalStream output) throws IOException {
  8790. output.registerLinkTarget(bignum);
  8791. output.write(bignum.value.signum() >= 0 ? '+' : '-');
  8792. BigInteger absValue = bignum.value.abs();
  8793. byte[] digits = absValue.toByteArray();
  8794. boolean oddLengthNonzeroStart = (digits.length % 2 != 0 && digits[0] != 0);
  8795. int shortLength = digits.length / 2;
  8796. if (oddLengthNonzeroStart) {
  8797. shortLength++;
  8798. }
  8799. output.writeInt(shortLength);
  8800. for (int i = 1; i <= shortLength * 2 && i <= digits.length; i++) {
  8801. output.write(digits[digits.length - i]);
  8802. }
  8803. if (oddLengthNonzeroStart) {
  8804. // Pad with a 0
  8805. output.write(0);
  8806. }
  8807. }
  8808. public static RubyNumeric unmarshalFrom(UnmarshalStream input) throws IOException {
  8809. boolean positive = input.readUnsignedByte() == '+';
  8810. int shortLength = input.unmarshalInt();
  8811. // BigInteger required a sign byte in incoming array
  8812. byte[] digits = new byte[shortLength * 2 + 1];
  8813. for (int i = digits.length - 1; i >= 1; i--) {
  8814. digits[i] = input.readSignedByte();
  8815. }
  8816. BigInteger value = new BigInteger(digits);
  8817. if (!positive) {
  8818. value = value.negate();
  8819. }
  8820. RubyNumeric result = bignorm(input.getRuntime(), value);
  8821. input.registerLinkTarget(result);
  8822. return result;
  8823. }
  8824. }
  8825. /***** BEGIN LICENSE BLOCK *****
  8826. * Version: CPL 1.0/GPL 2.0/LGPL 2.1
  8827. *
  8828. * The contents of this file are subject to the Common Public
  8829. * License Version 1.0 (the "License"); you may not use this file
  8830. * except in compliance with the License. You may obtain a copy of
  8831. * the License at http://www.eclipse.org/legal/cpl-v10.html
  8832. *
  8833. * Software distributed under the License is distributed on an "AS
  8834. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  8835. * implied. See the License for the specific language governing
  8836. * rights and limitations under the License.
  8837. *
  8838. * Copyright (C) 2001 Chad Fowler <chadfowler@chadfowler.com>
  8839. * Copyright (C) 2001 Alan Moore <alan_moore@gmx.net>
  8840. * Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
  8841. * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
  8842. * Copyright (C) 2002-2005 Thomas E Enebo <enebo@acm.org>
  8843. * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
  8844. * Copyright (C) 2005 Charles O Nutter <headius@headius.com>
  8845. *
  8846. * Alternatively, the contents of this file may be used under the terms of
  8847. * either of the GNU General Public License Version 2 or later (the "GPL"),
  8848. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  8849. * in which case the provisions of the GPL or the LGPL are applicable instead
  8850. * of those above. If you wish to allow use of your version of this file only
  8851. * under the terms of either the GPL or the LGPL, and not to allow others to
  8852. * use your version of this file under the terms of the CPL, indicate your
  8853. * decision by deleting the provisions above and replace them with the notice
  8854. * and other provisions required by the GPL or the LGPL. If you do not delete
  8855. * the provisions above, a recipient may use your version of this file under
  8856. * the terms of any one of the CPL, the GPL or the LGPL.
  8857. ***** END LICENSE BLOCK *****/
  8858. package org.jruby;
  8859. import org.jruby.anno.JRubyClass;
  8860. import org.jruby.anno.JRubyMethod;
  8861. import org.jruby.runtime.Binding;
  8862. import org.jruby.runtime.Frame;
  8863. import org.jruby.runtime.ObjectAllocator;
  8864. import org.jruby.runtime.ThreadContext;
  8865. import org.jruby.runtime.Visibility;
  8866. import org.jruby.runtime.builtin.IRubyObject;
  8867. /**
  8868. * @author jpetersen
  8869. */
  8870. @JRubyClass(name="Binding")
  8871. public class RubyBinding extends RubyObject {
  8872. private Binding binding;
  8873. public RubyBinding(Ruby runtime, RubyClass rubyClass, Binding binding) {
  8874. super(runtime, rubyClass);
  8875. this.binding = binding;
  8876. }
  8877. private RubyBinding(Ruby runtime, RubyClass rubyClass) {
  8878. super(runtime, rubyClass);
  8879. }
  8880. private static ObjectAllocator BINDING_ALLOCATOR = new ObjectAllocator() {
  8881. public IRubyObject allocate(Ruby runtime, RubyClass klass) {
  8882. RubyBinding instance = new RubyBinding(runtime, klass);
  8883. return instance;
  8884. }
  8885. };
  8886. public static RubyClass createBindingClass(Ruby runtime) {
  8887. RubyClass bindingClass = runtime.defineClass("Binding", runtime.getObject(), BINDING_ALLOCATOR);
  8888. runtime.setBinding(bindingClass);
  8889. bindingClass.defineAnnotatedMethods(RubyBinding.class);
  8890. return bindingClass;
  8891. }
  8892. public Binding getBinding() {
  8893. return binding;
  8894. }
  8895. // Proc class
  8896. public static RubyBinding newBinding(Ruby runtime, Binding binding) {
  8897. return new RubyBinding(runtime, runtime.getBinding(), binding);
  8898. }
  8899. public static RubyBinding newBinding(Ruby runtime) {
  8900. ThreadContext context = runtime.getCurrentContext();
  8901. // FIXME: We should be cloning, not reusing: frame, scope, dynvars, and potentially iter/block info
  8902. Frame frame = context.getCurrentFrame();
  8903. Binding binding = new Binding(frame, context.getBindingRubyClass(), context.getCurrentScope());
  8904. return new RubyBinding(runtime, runtime.getBinding(), binding);
  8905. }
  8906. /**
  8907. * Create a binding appropriate for a bare "eval", by using the previous (caller's) frame and current
  8908. * scope.
  8909. */
  8910. public static RubyBinding newBindingForEval(ThreadContext context) {
  8911. // This requires some explaining. We use Frame values when executing blocks to fill in
  8912. // various values in ThreadContext and EvalState.eval like rubyClass, cref, and self.
  8913. // Largely, for an eval that is using the logical binding at a place where the eval is
  8914. // called we mostly want to use the current frames value for this. Most importantly,
  8915. // we need that self (JRUBY-858) at this point. We also need to make sure that returns
  8916. // jump to the right place (which happens to be the previous frame). Lastly, we do not
  8917. // want the current frames klazz since that will be the klazz represented of self. We
  8918. // want the class right before the eval (well we could use cref class for this too I think).
  8919. // Once we end up having Frames created earlier I think the logic of stuff like this will
  8920. // be better since we won't be worried about setting Frame to setup other variables/stacks
  8921. // but just making sure Frame itself is correct...
  8922. Frame previousFrame = context.getPreviousFrame();
  8923. Frame currentFrame = context.getCurrentFrame();
  8924. currentFrame.setKlazz(previousFrame.getKlazz());
  8925. // Set jump target to whatever the previousTarget thinks is good.
  8926. // currentFrame.setJumpTarget(previousFrame.getJumpTarget() != null ? previousFrame.getJumpTarget() : previousFrame);
  8927. Binding binding = new Binding(previousFrame, context.getBindingRubyClass(), context.getCurrentScope());
  8928. Ruby runtime = context.getRuntime();
  8929. return new RubyBinding(runtime, runtime.getBinding(), binding);
  8930. }
  8931. @JRubyMethod(name = "initialize", visibility = Visibility.PRIVATE)
  8932. public IRubyObject initialize(ThreadContext context) {
  8933. // FIXME: We should be cloning, not reusing: frame, scope, dynvars, and potentially iter/block info
  8934. Frame frame = context.getCurrentFrame();
  8935. binding = new Binding(frame, context.getBindingRubyClass(), context.getCurrentScope());
  8936. return this;
  8937. }
  8938. @JRubyMethod(name = "initialize_copy", required = 1, visibility = Visibility.PRIVATE)
  8939. @Override
  8940. public IRubyObject initialize_copy(IRubyObject other) {
  8941. RubyBinding otherBinding = (RubyBinding)other;
  8942. binding = otherBinding.binding;
  8943. return this;
  8944. }
  8945. }
  8946. /*
  8947. ***** BEGIN LICENSE BLOCK *****
  8948. * Version: CPL 1.0/GPL 2.0/LGPL 2.1
  8949. *
  8950. * The contents of this file are subject to the Common Public
  8951. * License Version 1.0 (the "License"); you may not use this file
  8952. * except in compliance with the License. You may obtain a copy of
  8953. * the License at http://www.eclipse.org/legal/cpl-v10.html
  8954. *
  8955. * Software distributed under the License is distributed on an "AS
  8956. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  8957. * implied. See the License for the specific language governing
  8958. * rights and limitations under the License.
  8959. *
  8960. * Copyright (C) 2001 Alan Moore <alan_moore@gmx.net>
  8961. * Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
  8962. * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
  8963. * Copyright (C) 2004 Thomas E Enebo <enebo@acm.org>
  8964. * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
  8965. *
  8966. * Alternatively, the contents of this file may be used under the terms of
  8967. * either of the GNU General Public License Version 2 or later (the "GPL"),
  8968. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  8969. * in which case the provisions of the GPL or the LGPL are applicable instead
  8970. * of those above. If you wish to allow use of your version of this file only
  8971. * under the terms of either the GPL or the LGPL, and not to allow others to
  8972. * use your version of this file under the terms of the CPL, indicate your
  8973. * decision by deleting the provisions above and replace them with the notice
  8974. * and other provisions required by the GPL or the LGPL. If you do not delete
  8975. * the provisions above, a recipient may use your version of this file under
  8976. * the terms of any one of the CPL, the GPL or the LGPL.
  8977. ***** END LICENSE BLOCK *****/
  8978. package org.jruby;
  8979. import org.jruby.anno.JRubyClass;
  8980. import org.jruby.anno.JRubyMethod;
  8981. import org.jruby.runtime.ClassIndex;
  8982. import org.jruby.runtime.ObjectAllocator;
  8983. import org.jruby.runtime.ThreadContext;
  8984. import org.jruby.runtime.builtin.IRubyObject;
  8985. import org.jruby.runtime.marshal.MarshalStream;
  8986. /**
  8987. *
  8988. * @author jpetersen
  8989. */
  8990. @JRubyClass(name={"TrueClass", "FalseClass"})
  8991. public class RubyBoolean extends RubyObject {
  8992. public RubyBoolean(Ruby runtime, boolean value) {
  8993. super(runtime, (value ? runtime.getTrueClass() : runtime.getFalseClass()), // Don't initialize with class
  8994. false); // Don't put in object space
  8995. if (!value) flags = FALSE_F;
  8996. }
  8997. @Override
  8998. public int getNativeTypeIndex() {
  8999. return (flags & FALSE_F) == 0 ? ClassIndex.TRUE : ClassIndex.FALSE;
  9000. }
  9001. @Override
  9002. public boolean isImmediate() {
  9003. return true;
  9004. }
  9005. @Override
  9006. public RubyClass getSingletonClass() {
  9007. return metaClass;
  9008. }
  9009. @Override
  9010. public Class<?> getJavaClass() {
  9011. return boolean.class;
  9012. }
  9013. public static RubyClass createFalseClass(Ruby runtime) {
  9014. RubyClass falseClass = runtime.defineClass("FalseClass", runtime.getObject(), ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);
  9015. runtime.setFalseClass(falseClass);
  9016. falseClass.index = ClassIndex.FALSE;
  9017. falseClass.defineAnnotatedMethods(False.class);
  9018. falseClass.getMetaClass().undefineMethod("new");
  9019. return falseClass;
  9020. }
  9021. public static RubyClass createTrueClass(Ruby runtime) {
  9022. RubyClass trueClass = runtime.defineClass("TrueClass", runtime.getObject(), ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);
  9023. runtime.setTrueClass(trueClass);
  9024. trueClass.index = ClassIndex.TRUE;
  9025. trueClass.defineAnnotatedMethods(True.class);
  9026. trueClass.getMetaClass().undefineMethod("new");
  9027. return trueClass;
  9028. }
  9029. public static RubyBoolean newBoolean(Ruby runtime, boolean value) {
  9030. return value ? runtime.getTrue() : runtime.getFalse();
  9031. }
  9032. public static class False {
  9033. @JRubyMethod(name = "&")
  9034. public static IRubyObject false_and(IRubyObject f, IRubyObject oth) {
  9035. return f;
  9036. }
  9037. @JRubyMethod(name = "|")
  9038. public static IRubyObject false_or(IRubyObject f, IRubyObject oth) {
  9039. return oth.isTrue() ? f.getRuntime().getTrue() : f;
  9040. }
  9041. @JRubyMethod(name = "^")
  9042. public static IRubyObject false_xor(IRubyObject f, IRubyObject oth) {
  9043. return oth.isTrue() ? f.getRuntime().getTrue() : f;
  9044. }
  9045. @JRubyMethod(name = "to_s")
  9046. public static IRubyObject false_to_s(IRubyObject f) {
  9047. return f.getRuntime().newString("false");
  9048. }
  9049. }
  9050. public static class True {
  9051. @JRubyMethod(name = "&")
  9052. public static IRubyObject true_and(IRubyObject t, IRubyObject oth) {
  9053. return oth.isTrue() ? t : t.getRuntime().getFalse();
  9054. }
  9055. @JRubyMethod(name = "|")
  9056. public static IRubyObject true_or(IRubyObject t, IRubyObject oth) {
  9057. return t;
  9058. }
  9059. @JRubyMethod(name = "^")
  9060. public static IRubyObject true_xor(IRubyObject t, IRubyObject oth) {
  9061. return oth.isTrue() ? t.getRuntime().getFalse() : t;
  9062. }
  9063. @JRubyMethod(name = "to_s")
  9064. public static IRubyObject true_to_s(IRubyObject t) {
  9065. return t.getRuntime().newString("true");
  9066. }
  9067. }
  9068. @Override
  9069. public RubyFixnum id() {
  9070. if ((flags & FALSE_F) == 0) {
  9071. return RubyFixnum.newFixnum(getRuntime(), 2);
  9072. } else {
  9073. return RubyFixnum.zero(getRuntime());
  9074. }
  9075. }
  9076. @Override
  9077. public IRubyObject taint(ThreadContext context) {
  9078. return this;
  9079. }
  9080. @Override
  9081. public IRubyObject freeze(ThreadContext context) {
  9082. return this;
  9083. }
  9084. public void marshalTo(MarshalStream output) throws java.io.IOException {
  9085. output.write(isTrue() ? 'T' : 'F');
  9086. }
  9087. }
  9088. /***** BEGIN LICENSE BLOCK *****
  9089. * Version: CPL 1.0/GPL 2.0/LGPL 2.1
  9090. *
  9091. * The contents of this file are subject to the Common Public
  9092. * License Version 1.0 (the "License"); you may not use this file
  9093. * except in compliance with the License. You may obtain a copy of
  9094. * the License at http://www.eclipse.org/legal/cpl-v10.html
  9095. *
  9096. * Software distributed under the License is distributed on an "AS
  9097. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9098. * implied. See the License for the specific language governing
  9099. * rights and limitations under the License.
  9100. *
  9101. * Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
  9102. * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
  9103. * Copyright (C) 2004-2005 Thomas E Enebo <enebo@acm.org>
  9104. * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
  9105. *
  9106. * Alternatively, the contents of this file may be used under the terms of
  9107. * either of the GNU General Public License Version 2 or later (the "GPL"),
  9108. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  9109. * in which case the provisions of the GPL or the LGPL are applicable instead
  9110. * of those above. If you wish to allow use of your version of this file only
  9111. * under the terms of either the GPL or the LGPL, and not to allow others to
  9112. * use your version of this file under the terms of the CPL, indicate your
  9113. * decision by deleting the provisions above and replace them with the notice
  9114. * and other provisions required by the GPL or the LGPL. If you do not delete
  9115. * the provisions above, a recipient may use your version of this file under
  9116. * the terms of any one of the CPL, the GPL or the LGPL.
  9117. ***** END LICENSE BLOCK *****/
  9118. package org.jruby;
  9119. import java.io.IOException;
  9120. import java.util.ArrayList;
  9121. import java.util.Collection;
  9122. import java.util.Collections;
  9123. import java.util.Set;
  9124. import org.jruby.anno.JRubyMethod;
  9125. import org.jruby.anno.JRubyClass;
  9126. import org.jruby.internal.runtime.methods.DynamicMethod;
  9127. import org.jruby.internal.runtime.methods.JavaMethod;
  9128. import org.jruby.javasupport.util.RuntimeHelpers;
  9129. import org.jruby.runtime.Block;
  9130. import org.jruby.runtime.CallSite;
  9131. import org.jruby.runtime.CallSite.InlineCachingCallSite;
  9132. import org.jruby.runtime.CallType;
  9133. import org.jruby.runtime.ClassIndex;
  9134. import org.jruby.runtime.ObjectAllocator;
  9135. import org.jruby.runtime.ObjectMarshal;
  9136. import org.jruby.runtime.ThreadContext;
  9137. import org.jruby.runtime.Visibility;
  9138. import org.jruby.runtime.builtin.IRubyObject;
  9139. import org.jruby.runtime.marshal.MarshalStream;
  9140. import org.jruby.runtime.marshal.UnmarshalStream;
  9141. import org.jruby.util.collections.WeakHashSet;
  9142. /**
  9143. *
  9144. * @author jpetersen
  9145. */
  9146. @JRubyClass(name="Class", parent="Module")
  9147. public class RubyClass extends RubyModule {
  9148. public static final int CS_IDX_INITIALIZE = 0;
  9149. public static final String[] CS_NAMES = {
  9150. "initialize"
  9151. };
  9152. private final CallSite[] baseCallSites = new CallSite[CS_NAMES.length];
  9153. {
  9154. for(int i = 0; i < CS_NAMES.length; i++) {
  9155. baseCallSites[i] = new InlineCachingCallSite(CS_NAMES[i], CallType.FUNCTIONAL);
  9156. }
  9157. }
  9158. private CallSite[] extraCallSites;
  9159. public static void createClassClass(Ruby runtime, RubyClass classClass) {
  9160. classClass.index = ClassIndex.CLASS;
  9161. classClass.kindOf = new RubyModule.KindOf() {
  9162. @Override
  9163. public boolean isKindOf(IRubyObject obj, RubyModule type) {
  9164. return obj instanceof RubyClass;
  9165. }
  9166. };
  9167. classClass.undefineMethod("module_function");
  9168. classClass.undefineMethod("append_features");
  9169. classClass.undefineMethod("extend_object");
  9170. classClass.defineAnnotatedMethods(RubyClass.class);
  9171. classClass.addMethod("new", new SpecificArityNew(classClass, Visibility.PUBLIC));
  9172. // This is a non-standard method; have we decided to start extending Ruby?
  9173. //classClass.defineFastMethod("subclasses", callbackFactory.getFastOptMethod("subclasses"));
  9174. // FIXME: for some reason this dispatcher causes a VerifyError...
  9175. //classClass.dispatcher = callbackFactory.createDispatcher(classClass);
  9176. }
  9177. public static final ObjectAllocator CLASS_ALLOCATOR = new ObjectAllocator() {
  9178. public IRubyObject allocate(Ruby runtime, RubyClass klass) {
  9179. RubyClass clazz = new RubyClass(runtime);
  9180. clazz.allocator = ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR; // Class.allocate object is not allocatable before it is initialized
  9181. return clazz;
  9182. }
  9183. };
  9184. public ObjectAllocator getAllocator() {
  9185. return allocator;
  9186. }
  9187. public void setAllocator(ObjectAllocator allocator) {
  9188. this.allocator = allocator;
  9189. }
  9190. @JRubyMethod(name = "allocate")
  9191. public IRubyObject allocate() {
  9192. if (superClass == null) throw runtime.newTypeError("can't instantiate uninitialized class");
  9193. IRubyObject obj = allocator.allocate(runtime, this);
  9194. if (obj.getMetaClass().getRealClass() != getRealClass()) throw runtime.newTypeError("wrong instance allocation");
  9195. return obj;
  9196. }
  9197. public CallSite[] getBaseCallSites() {
  9198. return baseCallSites;
  9199. }
  9200. public CallSite[] getExtraCallSites() {
  9201. return extraCallSites;
  9202. }
  9203. @Override
  9204. public int getNativeTypeIndex() {
  9205. return ClassIndex.CLASS;
  9206. }
  9207. @Override
  9208. public boolean isModule() {
  9209. return false;
  9210. }
  9211. @Override
  9212. public boolean isClass() {
  9213. return true;
  9214. }
  9215. @Override
  9216. public boolean isSingleton() {
  9217. return false;
  9218. }
  9219. /** boot_defclass
  9220. * Create an initial Object meta class before Module and Kernel dependencies have
  9221. * squirreled themselves together.
  9222. *
  9223. * @param runtime we need it
  9224. * @return a half-baked meta class for object
  9225. */
  9226. public static RubyClass createBootstrapClass(Ruby runtime, String name, RubyClass superClass, ObjectAllocator allocator) {
  9227. RubyClass obj;
  9228. if (superClass == null ) { // boot the Object class
  9229. obj = new RubyClass(runtime);
  9230. obj.marshal = DEFAULT_OBJECT_MARSHAL;
  9231. } else { // boot the Module and Class classes
  9232. obj = new RubyClass(runtime, superClass);
  9233. }
  9234. obj.setAllocator(allocator);
  9235. obj.setBaseName(name);
  9236. return obj;
  9237. }
  9238. private final Ruby runtime;
  9239. private ObjectAllocator allocator; // the default allocator
  9240. protected ObjectMarshal marshal;
  9241. private Set<RubyClass> subclasses;
  9242. /** separate path for MetaClass and IncludedModuleWrapper construction
  9243. * (rb_class_boot version for MetaClasses)
  9244. * no marshal, allocator initialization and addSubclass(this) here!
  9245. */
  9246. protected RubyClass(Ruby runtime, RubyClass superClass, boolean objectSpace) {
  9247. super(runtime, runtime.getClassClass(), objectSpace);
  9248. this.runtime = runtime;
  9249. this.superClass = superClass; // this is the only case it might be null here (in MetaClass construction)
  9250. }
  9251. /** used by CLASS_ALLOCATOR (any Class' class will be a Class!)
  9252. * also used to bootstrap Object class
  9253. */
  9254. protected RubyClass(Ruby runtime) {
  9255. super(runtime, runtime.getClassClass());
  9256. this.runtime = runtime;
  9257. index = ClassIndex.CLASS;
  9258. }
  9259. /** rb_class_boot (for plain Classes)
  9260. * also used to bootstrap Module and Class classes
  9261. */
  9262. protected RubyClass(Ruby runtime, RubyClass superClazz) {
  9263. this(runtime);
  9264. superClass = superClazz;
  9265. marshal = superClazz.marshal; // use parent's marshal
  9266. superClazz.addSubclass(this);
  9267. infectBy(superClass);
  9268. }
  9269. /**
  9270. * A constructor which allows passing in an array of supplementary call sites.
  9271. */
  9272. protected RubyClass(Ruby runtime, RubyClass superClazz, CallSite[] extraCallSites) {
  9273. this(runtime);
  9274. this.superClass = superClazz;
  9275. this.marshal = superClazz.marshal; // use parent's marshal
  9276. superClazz.addSubclass(this);
  9277. this.extraCallSites = extraCallSites;
  9278. infectBy(superClass);
  9279. }
  9280. /**
  9281. * Construct a new class with the given name scoped under Object (global)
  9282. * and with Object as its immediate superclass.
  9283. * Corresponds to rb_class_new in MRI.
  9284. */
  9285. public static RubyClass newClass(Ruby runtime, RubyClass superClass) {
  9286. if (superClass == runtime.getClassClass()) throw runtime.newTypeError("can't make subclass of Class");
  9287. if (superClass.isSingleton()) throw runtime.newTypeError("can't make subclass of virtual class");
  9288. return new RubyClass(runtime, superClass);
  9289. }
  9290. /**
  9291. * A variation on newClass that allow passing in an array of supplementary
  9292. * call sites to improve dynamic invocation.
  9293. */
  9294. public static RubyClass newClass(Ruby runtime, RubyClass superClass, CallSite[] extraCallSites) {
  9295. if (superClass == runtime.getClassClass()) throw runtime.newTypeError("can't make subclass of Class");
  9296. if (superClass.isSingleton()) throw runtime.newTypeError("can't make subclass of virtual class");
  9297. return new RubyClass(runtime, superClass, extraCallSites);
  9298. }
  9299. /**
  9300. * Construct a new class with the given name, allocator, parent class,
  9301. * and containing class. If setParent is true, the class's parent will be
  9302. * explicitly set to the provided parent (rather than the new class just
  9303. * being assigned to a constant in that parent).
  9304. * Corresponds to rb_class_new/rb_define_class_id/rb_name_class/rb_set_class_path
  9305. * in MRI.
  9306. */
  9307. public static RubyClass newClass(Ruby runtime, RubyClass superClass, String name, ObjectAllocator allocator, RubyModule parent, boolean setParent) {
  9308. RubyClass clazz = newClass(runtime, superClass);
  9309. clazz.setBaseName(name);
  9310. clazz.setAllocator(allocator);
  9311. clazz.makeMetaClass(superClass.getMetaClass());
  9312. if (setParent) clazz.setParent(parent);
  9313. parent.setConstant(name, clazz);
  9314. clazz.inherit(superClass);
  9315. return clazz;
  9316. }
  9317. /**
  9318. * A variation on newClass that allows passing in an array of supplementary
  9319. * call sites to improve dynamic invocation performance.
  9320. */
  9321. public static RubyClass newClass(Ruby runtime, RubyClass superClass, String name, ObjectAllocator allocator, RubyModule parent, boolean setParent, CallSite[] extraCallSites) {
  9322. RubyClass clazz = newClass(runtime, superClass, extraCallSites);
  9323. clazz.setBaseName(name);
  9324. clazz.setAllocator(allocator);
  9325. clazz.makeMetaClass(superClass.getMetaClass());
  9326. if (setParent) clazz.setParent(parent);
  9327. parent.setConstant(name, clazz);
  9328. clazz.inherit(superClass);
  9329. return clazz;
  9330. }
  9331. /** rb_make_metaclass
  9332. *
  9333. */
  9334. @Override
  9335. public RubyClass makeMetaClass(RubyClass superClass) {
  9336. if (isSingleton()) { // could be pulled down to RubyClass in future
  9337. MetaClass klass = new MetaClass(getRuntime(), superClass); // rb_class_boot
  9338. setMetaClass(klass);
  9339. klass.setAttached(this);
  9340. klass.setMetaClass(klass);
  9341. klass.setSuperClass(getSuperClass().getRealClass().getMetaClass());
  9342. return klass;
  9343. } else {
  9344. return super.makeMetaClass(superClass);
  9345. }
  9346. }
  9347. @Deprecated
  9348. public IRubyObject invoke(ThreadContext context, IRubyObject self, int methodIndex, String name, IRubyObject[] args, CallType callType, Block block) {
  9349. return invoke(context, self, name, args, callType, block);
  9350. }
  9351. public boolean notVisibleAndNotMethodMissing(DynamicMethod method, String name, IRubyObject caller, CallType callType) {
  9352. return !method.isCallableFrom(caller, callType) && !name.equals("method_missing");
  9353. }
  9354. public IRubyObject invoke(ThreadContext context, IRubyObject self, String name,
  9355. CallType callType, Block block) {
  9356. DynamicMethod method = searchMethod(name);
  9357. IRubyObject caller = context.getFrameSelf();
  9358. if (shouldCallMethodMissing(method, name, caller, callType)) {
  9359. return RuntimeHelpers.callMethodMissing(context, self, method, name, caller, callType, block);
  9360. }
  9361. return method.call(context, self, this, name, block);
  9362. }
  9363. public IRubyObject finvoke(ThreadContext context, IRubyObject self, String name, Block block) {
  9364. DynamicMethod method = searchMethod(name);
  9365. if (shouldCallMethodMissing(method)) {
  9366. return RuntimeHelpers.callMethodMissing(context, self, method, name, context.getFrameSelf(), CallType.FUNCTIONAL, block);
  9367. }
  9368. return method.call(context, self, this, name, block);
  9369. }
  9370. public IRubyObject invoke(ThreadContext context, IRubyObject self, String name,
  9371. IRubyObject[] args, CallType callType, Block block) {
  9372. assert args != null;
  9373. DynamicMethod method = searchMethod(name);
  9374. IRubyObject caller = context.getFrameSelf();
  9375. if (shouldCallMethodMissing(method, name, caller, callType)) {
  9376. return RuntimeHelpers.callMethodMissing(context, self, method, name, args, caller, callType, block);
  9377. }
  9378. return method.call(context, self, this, name, args, block);
  9379. }
  9380. public IRubyObject finvoke(ThreadContext context, IRubyObject self, String name,
  9381. IRubyObject[] args, Block block) {
  9382. assert args != null;
  9383. DynamicMethod method = searchMethod(name);
  9384. if (shouldCallMethodMissing(method)) {
  9385. return RuntimeHelpers.callMethodMissing(context, self, method, name, args, context.getFrameSelf(), CallType.FUNCTIONAL, block);
  9386. }
  9387. return method.call(context, self, this, name, args, block);
  9388. }
  9389. public IRubyObject invoke(ThreadContext context, IRubyObject self, String name,
  9390. IRubyObject arg, CallType callType, Block block) {
  9391. DynamicMethod method = searchMethod(name);
  9392. IRubyObject caller = context.getFrameSelf();
  9393. if (shouldCallMethodMissing(method, name, caller, callType)) {
  9394. return RuntimeHelpers.callMethodMissing(context, self, method, name, arg, caller, callType, block);
  9395. }
  9396. return method.call(context, self, this, name, arg, block);
  9397. }
  9398. public IRubyObject finvoke(ThreadContext context, IRubyObject self, String name,
  9399. IRubyObject arg, Block block) {
  9400. DynamicMethod method = searchMethod(name);
  9401. if (shouldCallMethodMissing(method)) {
  9402. return RuntimeHelpers.callMethodMissing(context, self, method, name, arg, context.getFrameSelf(), CallType.FUNCTIONAL, block);
  9403. }
  9404. return method.call(context, self, this, name, arg, block);
  9405. }
  9406. public IRubyObject invoke(ThreadContext context, IRubyObject self, String name,
  9407. IRubyObject arg0, IRubyObject arg1, CallType callType, Block block) {
  9408. DynamicMethod method = searchMethod(name);
  9409. IRubyObject caller = context.getFrameSelf();
  9410. if (shouldCallMethodMissing(method, name, caller, callType)) {
  9411. return RuntimeHelpers.callMethodMissing(context, self, method, name, arg0, arg1, caller, callType, block);
  9412. }
  9413. return method.call(context, self, this, name, arg0, arg1, block);
  9414. }
  9415. public IRubyObject finvoke(ThreadContext context, IRubyObject self, String name,
  9416. IRubyObject arg0, IRubyObject arg1, Block block) {
  9417. DynamicMethod method = searchMethod(name);
  9418. if (shouldCallMethodMissing(method)) {
  9419. return RuntimeHelpers.callMethodMissing(context, self, method, name, arg0, arg1, context.getFrameSelf(), CallType.FUNCTIONAL, block);
  9420. }
  9421. return method.call(context, self, this, name, arg0, arg1, block);
  9422. }
  9423. public IRubyObject invoke(ThreadContext context, IRubyObject self, String name,
  9424. IRubyObject arg0, IRubyObject arg1, IRubyObject arg2, CallType callType, Block block) {
  9425. DynamicMethod method = searchMethod(name);
  9426. IRubyObject caller = context.getFrameSelf();
  9427. if (shouldCallMethodMissing(method, name, caller, callType)) {
  9428. return RuntimeHelpers.callMethodMissing(context, self, method, name, arg0, arg1, arg2, caller, callType, block);
  9429. }
  9430. return method.call(context, self, this, name, arg0, arg1, arg2, block);
  9431. }
  9432. public IRubyObject finvoke(ThreadContext context, IRubyObject self, String name,
  9433. IRubyObject arg0, IRubyObject arg1, IRubyObject arg2, Block block) {
  9434. DynamicMethod method = searchMethod(name);
  9435. if (shouldCallMethodMissing(method)) {
  9436. return RuntimeHelpers.callMethodMissing(context, self, method, name, arg0, arg1, arg2, context.getFrameSelf(), CallType.FUNCTIONAL, block);
  9437. }
  9438. return method.call(context, self, this, name, arg0, arg1, arg2, block);
  9439. }
  9440. public IRubyObject invoke(ThreadContext context, IRubyObject self, String name,
  9441. CallType callType) {
  9442. DynamicMethod method = searchMethod(name);
  9443. IRubyObject caller = context.getFrameSelf();
  9444. if (shouldCallMethodMissing(method, name, caller, callType)) {
  9445. return RuntimeHelpers.callMethodMissing(context, self, method, name, caller, callType, Block.NULL_BLOCK);
  9446. }
  9447. return method.call(context, self, this, name);
  9448. }
  9449. public IRubyObject finvoke(ThreadContext context, IRubyObject self, String name) {
  9450. DynamicMethod method = searchMethod(name);
  9451. if (shouldCallMethodMissing(method)) {
  9452. return RuntimeHelpers.callMethodMissing(context, self, method, name, context.getFrameSelf(), CallType.FUNCTIONAL, Block.NULL_BLOCK);
  9453. }
  9454. return method.call(context, self, this, name);
  9455. }
  9456. public IRubyObject invoke(ThreadContext context, IRubyObject self, String name,
  9457. IRubyObject[] args, CallType callType) {
  9458. assert args != null;
  9459. DynamicMethod method = searchMethod(name);
  9460. IRubyObject caller = context.getFrameSelf();
  9461. if (shouldCallMethodMissing(method, name, caller, callType)) {
  9462. return RuntimeHelpers.callMethodMissing(context, self, method, name, args, caller, callType, Block.NULL_BLOCK);
  9463. }
  9464. return method.call(context, self, this, name, args);
  9465. }
  9466. public IRubyObject finvoke(ThreadContext context, IRubyObject self, String name,
  9467. IRubyObject[] args) {
  9468. assert args != null;
  9469. DynamicMethod method = searchMethod(name);
  9470. if (shouldCallMethodMissing(method)) {
  9471. return RuntimeHelpers.callMethodMissing(context, self, method, name, args, context.getFrameSelf(), CallType.FUNCTIONAL, Block.NULL_BLOCK);
  9472. }
  9473. return method.call(context, self, this, name, args);
  9474. }
  9475. public IRubyObject invoke(ThreadContext context, IRubyObject self, String name,
  9476. IRubyObject arg, CallType callType) {
  9477. DynamicMethod method = searchMethod(name);
  9478. IRubyObject caller = context.getFrameSelf();
  9479. if (shouldCallMethodMissing(method, name, caller, callType)) {
  9480. return RuntimeHelpers.callMethodMissing(context, self, method, name, arg, caller, callType, Block.NULL_BLOCK);
  9481. }
  9482. return method.call(context, self, this, name, arg);
  9483. }
  9484. public IRubyObject finvoke(ThreadContext context, IRubyObject self, String name,
  9485. IRubyObject arg) {
  9486. DynamicMethod method = searchMethod(name);
  9487. if (shouldCallMethodMissing(method)) {
  9488. return RuntimeHelpers.callMethodMissing(context, self, method, name, arg, context.getFrameSelf(), CallType.FUNCTIONAL, Block.NULL_BLOCK);
  9489. }
  9490. return method.call(context, self, this, name, arg);
  9491. }
  9492. public IRubyObject invoke(ThreadContext context, IRubyObject self, String name,
  9493. IRubyObject arg0, IRubyObject arg1, CallType callType) {
  9494. DynamicMethod method = searchMethod(name);
  9495. IRubyObject caller = context.getFrameSelf();
  9496. if (shouldCallMethodMissing(method, name, caller, callType)) {
  9497. return RuntimeHelpers.callMethodMissing(context, self, method, name, arg0, arg1, caller, callType, Block.NULL_BLOCK);
  9498. }
  9499. return method.call(context, self, this, name, arg0, arg1);
  9500. }
  9501. public IRubyObject finvoke(ThreadContext context, IRubyObject self, String name,
  9502. IRubyObject arg0, IRubyObject arg1) {
  9503. DynamicMethod method = searchMethod(name);
  9504. if (shouldCallMethodMissing(method)) {
  9505. return RuntimeHelpers.callMethodMissing(context, self, method, name, arg0, arg1, context.getFrameSelf(), CallType.FUNCTIONAL, Block.NULL_BLOCK);
  9506. }
  9507. return method.call(context, self, this, name, arg0, arg1);
  9508. }
  9509. public IRubyObject invoke(ThreadContext context, IRubyObject self, String name,
  9510. IRubyObject arg0, IRubyObject arg1, IRubyObject arg2, CallType callType) {
  9511. DynamicMethod method = searchMethod(name);
  9512. IRubyObject caller = context.getFrameSelf();
  9513. if (shouldCallMethodMissing(method, name, caller, callType)) {
  9514. return RuntimeHelpers.callMethodMissing(context, self, method, name, arg0, arg1, arg2, caller, callType, Block.NULL_BLOCK);
  9515. }
  9516. return method.call(context, self, this, name, arg0, arg1, arg2);
  9517. }
  9518. public IRubyObject finvoke(ThreadContext context, IRubyObject self, String name,
  9519. IRubyObject arg0, IRubyObject arg1, IRubyObject arg2) {
  9520. DynamicMethod method = searchMethod(name);
  9521. if (shouldCallMethodMissing(method)) {
  9522. return RuntimeHelpers.callMethodMissing(context, self, method, name, arg0, arg1, arg2, context.getFrameSelf(), CallType.FUNCTIONAL, Block.NULL_BLOCK);
  9523. }
  9524. return method.call(context, self, this, name, arg0, arg1, arg2);
  9525. }
  9526. private boolean shouldCallMethodMissing(DynamicMethod method) {
  9527. return method.isUndefined();
  9528. }
  9529. private boolean shouldCallMethodMissing(DynamicMethod method, String name, IRubyObject caller, CallType callType) {
  9530. return method.isUndefined() || notVisibleAndNotMethodMissing(method, name, caller, callType);
  9531. }
  9532. public IRubyObject invokeInherited(ThreadContext context, IRubyObject self, IRubyObject subclass) {
  9533. DynamicMethod method = getMetaClass().searchMethod("inherited");
  9534. if (method.isUndefined()) {
  9535. return RuntimeHelpers.callMethodMissing(context, self, method, "inherited", subclass, context.getFrameSelf(), CallType.FUNCTIONAL, Block.NULL_BLOCK);
  9536. }
  9537. return method.call(context, self, getMetaClass(), "inherited", subclass, Block.NULL_BLOCK);
  9538. }
  9539. /** rb_class_new_instance
  9540. *
  9541. */
  9542. public IRubyObject newInstance(ThreadContext context, IRubyObject[] args, Block block) {
  9543. IRubyObject obj = allocate();
  9544. baseCallSites[CS_IDX_INITIALIZE].call(context, obj, args, block);
  9545. return obj;
  9546. }
  9547. // TODO: replace this with a smarter generated invoker that can handle 0-N args
  9548. public static class SpecificArityNew extends JavaMethod {
  9549. public SpecificArityNew(RubyModule implClass, Visibility visibility) {
  9550. super(implClass, visibility);
  9551. }
  9552. public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject[] args, Block block) {
  9553. RubyClass cls = (RubyClass)self;
  9554. IRubyObject obj = cls.allocate();
  9555. cls.baseCallSites[CS_IDX_INITIALIZE].call(context, obj, args, block);
  9556. return obj;
  9557. }
  9558. public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, Block block) {
  9559. RubyClass cls = (RubyClass)self;
  9560. IRubyObject obj = cls.allocate();
  9561. cls.baseCallSites[CS_IDX_INITIALIZE].call(context, obj, block);
  9562. return obj;
  9563. }
  9564. public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0, Block block) {
  9565. RubyClass cls = (RubyClass)self;
  9566. IRubyObject obj = cls.allocate();
  9567. cls.baseCallSites[CS_IDX_INITIALIZE].call(context, obj, arg0, block);
  9568. return obj;
  9569. }
  9570. public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0, IRubyObject arg1, Block block) {
  9571. RubyClass cls = (RubyClass)self;
  9572. IRubyObject obj = cls.allocate();
  9573. cls.baseCallSites[CS_IDX_INITIALIZE].call(context, obj, arg0, arg1, block);
  9574. return obj;
  9575. }
  9576. public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2, Block block) {
  9577. RubyClass cls = (RubyClass)self;
  9578. IRubyObject obj = cls.allocate();
  9579. cls.baseCallSites[CS_IDX_INITIALIZE].call(context, obj, arg0, arg1, arg2, block);
  9580. return obj;
  9581. }
  9582. }
  9583. /** rb_class_initialize
  9584. *
  9585. */
  9586. @JRubyMethod(name = "initialize", optional = 1, frame = true, visibility = Visibility.PRIVATE)
  9587. public IRubyObject initialize(IRubyObject[] args, Block block) {
  9588. if (superClass != null) {
  9589. throw getRuntime().newTypeError("already initialized class");
  9590. }
  9591. IRubyObject superObject;
  9592. if (args.length == 0) {
  9593. superObject = getRuntime().getObject();
  9594. } else {
  9595. superObject = args[0];
  9596. checkInheritable(superObject);
  9597. }
  9598. RubyClass superClazz = (RubyClass) superObject;
  9599. superClass = superClazz;
  9600. allocator = superClazz.allocator;
  9601. makeMetaClass(superClazz.getMetaClass());
  9602. marshal = superClazz.marshal;
  9603. superClazz.addSubclass(this);
  9604. super.initialize(block);
  9605. inherit(superClazz);
  9606. return this;
  9607. }
  9608. /** rb_class_init_copy
  9609. *
  9610. */
  9611. @JRubyMethod(name = "initialize_copy", required = 1)
  9612. @Override
  9613. public IRubyObject initialize_copy(IRubyObject original){
  9614. if (superClass != null) throw runtime.newTypeError("already initialized class");
  9615. if (original instanceof MetaClass) throw getRuntime().newTypeError("can't copy singleton class");
  9616. super.initialize_copy(original);
  9617. allocator = ((RubyClass)original).allocator;
  9618. return this;
  9619. }
  9620. // TODO: Someday, enable.
  9621. // @JRubyMethod(name = "subclasses", optional = 1)
  9622. public IRubyObject subclasses(ThreadContext context, IRubyObject[] args) {
  9623. boolean recursive = false;
  9624. if (args.length == 1) {
  9625. if (args[0] instanceof RubyBoolean) {
  9626. recursive = args[0].isTrue();
  9627. } else {
  9628. context.getRuntime().newTypeError(args[0], context.getRuntime().fastGetClass("Boolean"));
  9629. }
  9630. }
  9631. return RubyArray.newArray(context.getRuntime(), subclasses(recursive)).freeze(context);
  9632. }
  9633. public Collection subclasses(boolean includeDescendants) {
  9634. if (subclasses != null) {
  9635. Collection<RubyClass> mine = new ArrayList<RubyClass>(subclasses);
  9636. if (includeDescendants) {
  9637. for (RubyClass i: subclasses) {
  9638. mine.addAll(i.subclasses(includeDescendants));
  9639. }
  9640. }
  9641. return mine;
  9642. } else {
  9643. return Collections.EMPTY_LIST;
  9644. }
  9645. }
  9646. public synchronized void addSubclass(RubyClass subclass) {
  9647. if (subclasses == null) subclasses = new WeakHashSet<RubyClass>();
  9648. subclasses.add(subclass);
  9649. }
  9650. public Ruby getClassRuntime() {
  9651. return runtime;
  9652. }
  9653. public RubyClass getRealClass() {
  9654. return this;
  9655. }
  9656. @JRubyMethod(name = "inherited", required = 1)
  9657. public IRubyObject inherited(ThreadContext context, IRubyObject arg) {
  9658. return context.getRuntime().getNil();
  9659. }
  9660. /** rb_class_inherited (reversed semantics!)
  9661. *
  9662. */
  9663. public void inherit(RubyClass superClazz) {
  9664. if (superClazz == null) superClazz = getRuntime().getObject();
  9665. superClazz.invokeInherited(getRuntime().getCurrentContext(), superClazz, this);
  9666. }
  9667. /** Return the real super class of this class.
  9668. *
  9669. * rb_class_superclass
  9670. *
  9671. */
  9672. @JRubyMethod(name = "superclass")
  9673. public IRubyObject superclass(ThreadContext context) {
  9674. RubyClass superClazz = superClass;
  9675. if (superClazz == null) throw context.getRuntime().newTypeError("uninitialized class");
  9676. if (isSingleton()) superClazz = metaClass;
  9677. while (superClazz != null && superClazz.isIncluded()) superClazz = superClazz.superClass;
  9678. return superClazz != null ? superClazz : context.getRuntime().getNil();
  9679. }
  9680. /** rb_check_inheritable
  9681. *
  9682. */
  9683. public static void checkInheritable(IRubyObject superClass) {
  9684. if (!(superClass instanceof RubyClass)) {
  9685. throw superClass.getRuntime().newTypeError("superclass must be a Class (" + superClass.getMetaClass() + " given)");
  9686. }
  9687. if (((RubyClass)superClass).isSingleton()) {
  9688. throw superClass.getRuntime().newTypeError("can't make subclass of virtual class");
  9689. }
  9690. }
  9691. public final ObjectMarshal getMarshal() {
  9692. return marshal;
  9693. }
  9694. public final void setMarshal(ObjectMarshal marshal) {
  9695. this.marshal = marshal;
  9696. }
  9697. public final void marshal(Object obj, MarshalStream marshalStream) throws IOException {
  9698. getMarshal().marshalTo(getRuntime(), obj, this, marshalStream);
  9699. }
  9700. public final Object unmarshal(UnmarshalStream unmarshalStream) throws IOException {
  9701. return getMarshal().unmarshalFrom(getRuntime(), this, unmarshalStream);
  9702. }
  9703. public static void marshalTo(RubyClass clazz, MarshalStream output) throws java.io.IOException {
  9704. output.registerLinkTarget(clazz);
  9705. output.writeString(MarshalStream.getPathFromClass(clazz));
  9706. }
  9707. public static RubyClass unmarshalFrom(UnmarshalStream input) throws java.io.IOException {
  9708. String name = RubyString.byteListToString(input.unmarshalString());
  9709. RubyClass result = UnmarshalStream.getClassFromPath(input.getRuntime(), name);
  9710. input.registerLinkTarget(result);
  9711. return result;
  9712. }
  9713. protected static final ObjectMarshal DEFAULT_OBJECT_MARSHAL = new ObjectMarshal() {
  9714. public void marshalTo(Ruby runtime, Object obj, RubyClass type,
  9715. MarshalStream marshalStream) throws IOException {
  9716. IRubyObject object = (IRubyObject)obj;
  9717. marshalStream.registerLinkTarget(object);
  9718. marshalStream.dumpVariables(object.getVariableList());
  9719. }
  9720. public Object unmarshalFrom(Ruby runtime, RubyClass type,
  9721. UnmarshalStream unmarshalStream) throws IOException {
  9722. IRubyObject result = type.allocate();
  9723. unmarshalStream.registerLinkTarget(result);
  9724. unmarshalStream.defaultVariablesUnmarshal(result);
  9725. return result;
  9726. }
  9727. };
  9728. }
  9729. /***** BEGIN LICENSE BLOCK *****
  9730. * Version: CPL 1.0/GPL 2.0/LGPL 2.1
  9731. *
  9732. * The contents of this file are subject to the Common Public
  9733. * License Version 1.0 (the "License"); you may not use this file
  9734. * except in compliance with the License. You may obtain a copy of
  9735. * the License at http://www.eclipse.org/legal/cpl-v10.html
  9736. *
  9737. * Software distributed under the License is distributed on an "AS
  9738. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9739. * implied. See the License for the specific language governing
  9740. * rights and limitations under the License.
  9741. *
  9742. * Copyright (C) 2007 Ola Bini <ola@ologix.com>
  9743. *
  9744. * Alternatively, the contents of this file may be used under the terms of
  9745. * either of the GNU General Public License Version 2 or later (the "GPL"),
  9746. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  9747. * in which case the provisions of the GPL or the LGPL are applicable instead
  9748. * of those above. If you wish to allow use of your version of this file only
  9749. * under the terms of either the GPL or the LGPL, and not to allow others to
  9750. * use your version of this file under the terms of the CPL, indicate your
  9751. * decision by deleting the provisions above and replace them with the notice
  9752. * and other provisions required by the GPL or the LGPL. If you do not delete
  9753. * the provisions above, a recipient may use your version of this file under
  9754. * the terms of any one of the CPL, the GPL or the LGPL.
  9755. ***** END LICENSE BLOCK *****/
  9756. package org.jruby;
  9757. import java.io.File;
  9758. import java.net.MalformedURLException;
  9759. import java.net.URL;
  9760. import org.jruby.anno.JRubyMethod;
  9761. import org.jruby.runtime.Block;
  9762. import org.jruby.runtime.ThreadContext;
  9763. import org.jruby.runtime.builtin.IRubyObject;
  9764. /**
  9765. * @author <a href="mailto:ola.bini@ki.se">Ola Bini</a>
  9766. */
  9767. public class RubyClassPathVariable extends RubyObject {
  9768. public static void createClassPathVariable(Ruby runtime) {
  9769. RubyClassPathVariable self = new RubyClassPathVariable(runtime);
  9770. runtime.getEnumerable().extend_object(self);
  9771. runtime.defineReadonlyVariable("$CLASSPATH", self);
  9772. self.getMetaClass().defineAnnotatedMethods(RubyClassPathVariable.class);
  9773. }
  9774. private RubyClassPathVariable(Ruby runtime) {
  9775. super(runtime, runtime.getObject());
  9776. }
  9777. @JRubyMethod(name = {"append", "<<"}, required = 1)
  9778. public IRubyObject append(IRubyObject obj) throws Exception {
  9779. String ss = obj.convertToString().toString();
  9780. URL url = getURL(ss);
  9781. getRuntime().getJRubyClassLoader().addURL(url);
  9782. return this;
  9783. }
  9784. private URL getURL(String target) throws MalformedURLException {
  9785. if(target.indexOf("://") == -1) {
  9786. return new File(target).toURI().toURL();
  9787. } else {
  9788. return new URL(target);
  9789. }
  9790. }
  9791. @JRubyMethod(name = {"size", "length"})
  9792. public IRubyObject size() {
  9793. return getRuntime().newFixnum(getRuntime().getJRubyClassLoader().getURLs().length);
  9794. }
  9795. @JRubyMethod(name = "each", frame = true)
  9796. public IRubyObject each(Block block) {
  9797. URL[] urls = getRuntime().getJRubyClassLoader().getURLs();
  9798. ThreadContext ctx = getRuntime().getCurrentContext();
  9799. for(int i=0,j=urls.length;i<j;i++) {
  9800. block.yield(ctx, getRuntime().newString(urls[i].toString()));
  9801. }
  9802. return getRuntime().getNil();
  9803. }
  9804. @JRubyMethod(name = "to_s")
  9805. public IRubyObject to_s() {
  9806. return callMethod(getRuntime().getCurrentContext(), "to_a").callMethod(getRuntime().getCurrentContext(), "to_s");
  9807. }
  9808. @JRubyMethod(name = "inspect")
  9809. public IRubyObject inspect() {
  9810. return callMethod(getRuntime().getCurrentContext(), "to_a").callMethod(getRuntime().getCurrentContext(), "inspect");
  9811. }
  9812. }// RubyClassPathVariable
  9813. /***** BEGIN LICENSE BLOCK *****
  9814. * Version: CPL 1.0/GPL 2.0/LGPL 2.1
  9815. *
  9816. * The contents of this file are subject to the Common Public
  9817. * License Version 1.0 (the "License"); you may not use this file
  9818. * except in compliance with the License. You may obtain a copy of
  9819. * the License at http://www.eclipse.org/legal/cpl-v10.html
  9820. *
  9821. * Software distributed under the License is distributed on an "AS
  9822. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9823. * implied. See the License for the specific language governing
  9824. * rights and limitations under the License.
  9825. *
  9826. * Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
  9827. * Copyright (C) 2002 Benoit Cerrina <b.cerrina@wanadoo.fr>
  9828. * Copyright (C) 2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
  9829. * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
  9830. * Copyright (C) 2005 Charles O Nutter <headius@headius.com>
  9831. * Copyright (C) 2006 Miguel Covarrubias <mlcovarrubias@gmail.com>
  9832. * Copyright (C) 2006 Thomas E Enebo <enebo@acm.org>
  9833. *
  9834. * Alternatively, the contents of this file may be used under the terms of
  9835. * either of the GNU General Public License Version 2 or later (the "GPL"),
  9836. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  9837. * in which case the provisions of the GPL or the LGPL are applicable instead
  9838. * of those above. If you wish to allow use of your version of this file only
  9839. * under the terms of either the GPL or the LGPL, and not to allow others to
  9840. * use your version of this file under the terms of the CPL, indicate your
  9841. * decision by deleting the provisions above and replace them with the notice
  9842. * and other provisions required by the GPL or the LGPL. If you do not delete
  9843. * the provisions above, a recipient may use your version of this file under
  9844. * the terms of any one of the CPL, the GPL or the LGPL.
  9845. ***** END LICENSE BLOCK *****/
  9846. package org.jruby;
  9847. import org.jruby.anno.JRubyMethod;
  9848. import org.jruby.anno.JRubyModule;
  9849. import org.jruby.exceptions.RaiseException;
  9850. import org.jruby.runtime.MethodIndex;
  9851. import org.jruby.runtime.ThreadContext;
  9852. import org.jruby.runtime.builtin.IRubyObject;
  9853. /** Implementation of the Comparable module.
  9854. *
  9855. */
  9856. @JRubyModule(name="Comparable")
  9857. public class RubyComparable {
  9858. public static RubyModule createComparable(Ruby runtime) {
  9859. RubyModule comparableModule = runtime.defineModule("Comparable");
  9860. runtime.setComparable(comparableModule);
  9861. comparableModule.defineAnnotatedMethods(RubyComparable.class);
  9862. return comparableModule;
  9863. }
  9864. /* ================
  9865. * Utility Methods
  9866. * ================
  9867. */
  9868. /** rb_cmpint
  9869. *
  9870. */
  9871. public static int cmpint(ThreadContext context, IRubyObject val, IRubyObject a, IRubyObject b) {
  9872. if (val.isNil()) cmperr(a, b);
  9873. if (val instanceof RubyFixnum) return RubyNumeric.fix2int((RubyFixnum) val);
  9874. if (val instanceof RubyBignum) return ((RubyBignum) val).getValue().signum() == -1 ? 1 : -1;
  9875. RubyFixnum zero = RubyFixnum.zero(context.getRuntime());
  9876. if (val.callMethod(context, MethodIndex.OP_GT, ">", zero).isTrue()) return 1;
  9877. if (val.callMethod(context, MethodIndex.OP_LT, "<", zero).isTrue()) return -1;
  9878. return 0;
  9879. }
  9880. /** rb_cmperr
  9881. *
  9882. */
  9883. public static IRubyObject cmperr(IRubyObject recv, IRubyObject other) {
  9884. IRubyObject target;
  9885. if (other.isImmediate() || !(other.isNil() || other.isTrue() || other == recv.getRuntime().getFalse())) {
  9886. target = other.inspect();
  9887. } else {
  9888. target = other.getType();
  9889. }
  9890. throw recv.getRuntime().newArgumentError("comparison of " + recv.getType() + " with " + target + " failed");
  9891. }
  9892. /* ================
  9893. * Module Methods
  9894. * ================
  9895. */
  9896. /** cmp_equal (cmp_eq inlined here)
  9897. *
  9898. */
  9899. @JRubyMethod(name = "==", required = 1)
  9900. public static IRubyObject op_equal(ThreadContext context, IRubyObject recv, IRubyObject other) {
  9901. Ruby runtime = context.getRuntime();
  9902. if (recv == other) return runtime.getTrue();
  9903. try {
  9904. IRubyObject result = recv.callMethod(context, MethodIndex.OP_SPACESHIP, "<=>", other);
  9905. return RubyBoolean.newBoolean(runtime, cmpint(context, result, recv, other) == 0);
  9906. } catch (RaiseException e) {
  9907. if (e.getException().kind_of_p(context, runtime.getStandardError()).isTrue()) {
  9908. return runtime.getNil();
  9909. } else {
  9910. throw e;
  9911. }
  9912. }
  9913. }
  9914. /** cmp_gt
  9915. *
  9916. */
  9917. // <=> may return nil in many circumstances, e.g. 3 <=> NaN
  9918. @JRubyMethod(name = ">", required = 1)
  9919. public static RubyBoolean op_gt(ThreadContext context, IRubyObject recv, IRubyObject other) {
  9920. IRubyObject result = recv.callMethod(context, MethodIndex.OP_SPACESHIP, "<=>", other);
  9921. if (result.isNil()) cmperr(recv, other);
  9922. return RubyBoolean.newBoolean(context.getRuntime(), cmpint(context, result, recv, other) > 0);
  9923. }
  9924. /** cmp_ge
  9925. *
  9926. */
  9927. @JRubyMethod(name = ">=", required = 1)
  9928. public static RubyBoolean op_ge(ThreadContext context, IRubyObject recv, IRubyObject other) {
  9929. IRubyObject result = recv.callMethod(context, MethodIndex.OP_SPACESHIP, "<=>", other);
  9930. if (result.isNil()) cmperr(recv, other);
  9931. return RubyBoolean.newBoolean(context.getRuntime(), cmpint(context, result, recv, other) >= 0);
  9932. }
  9933. /** cmp_lt
  9934. *
  9935. */
  9936. @JRubyMethod(name = "<", required = 1)
  9937. public static RubyBoolean op_lt(ThreadContext context, IRubyObject recv, IRubyObject other) {
  9938. IRubyObject result = recv.callMethod(context, MethodIndex.OP_SPACESHIP, "<=>", other);
  9939. if (result.isNil()) cmperr(recv, other);
  9940. return RubyBoolean.newBoolean(context.getRuntime(), cmpint(context, result, recv, other) < 0);
  9941. }
  9942. /** cmp_le
  9943. *
  9944. */
  9945. @JRubyMethod(name = "<=", required = 1)
  9946. public static RubyBoolean op_le(ThreadContext context, IRubyObject recv, IRubyObject other) {
  9947. IRubyObject result = recv.callMethod(context, MethodIndex.OP_SPACESHIP, "<=>", other);
  9948. if (result.isNil()) cmperr(recv, other);
  9949. return RubyBoolean.newBoolean(context.getRuntime(), cmpint(context, result, recv, other) <= 0);
  9950. }
  9951. /** cmp_between
  9952. *
  9953. */
  9954. @JRubyMethod(name = "between?", required = 2)
  9955. public static RubyBoolean between_p(ThreadContext context, IRubyObject recv, IRubyObject first, IRubyObject second) {
  9956. return context.getRuntime().newBoolean(op_lt(context, recv, first).isFalse() && op_gt(context, recv, second).isFalse());
  9957. }
  9958. }
  9959. /***** BEGIN LICENSE BLOCK *****
  9960. * Version: CPL 1.0/GPL 2.0/LGPL 2.1
  9961. *
  9962. * The contents of this file are subject to the Common Public
  9963. * License Version 1.0 (the "License"); you may not use this file
  9964. * except in compliance with the License. You may obtain a copy of
  9965. * the License at http://www.eclipse.org/legal/cpl-v10.html
  9966. *
  9967. * Software distributed under the License is distributed on an "AS
  9968. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9969. * implied. See the License for the specific language governing
  9970. * rights and limitations under the License.
  9971. *
  9972. * Alternatively, the contents of this file may be used under the terms of
  9973. * either of the GNU General Public License Version 2 or later (the "GPL"),
  9974. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  9975. * in which case the provisions of the GPL or the LGPL are applicable instead
  9976. * of those above. If you wish to allow use of your version of this file only
  9977. * under the terms of either the GPL or the LGPL, and not to allow others to
  9978. * use your version of this file under the terms of the CPL, indicate your
  9979. * decision by deleting the provisions above and replace them with the notice
  9980. * and other provisions required by the GPL or the LGPL. If you do not delete
  9981. * the provisions above, a recipient may use your version of this file under
  9982. * the terms of any one of the CPL, the GPL or the LGPL.
  9983. ***** END LICENSE BLOCK *****/
  9984. package org.jruby;
  9985. import static org.jruby.util.Numeric.f_abs;
  9986. import static org.jruby.util.Numeric.f_abs2;
  9987. import static org.jruby.util.Numeric.f_add;
  9988. import static org.jruby.util.Numeric.f_arg;
  9989. import static org.jruby.util.Numeric.f_conjugate;
  9990. import static org.jruby.util.Numeric.f_denominator;
  9991. import static org.jruby.util.Numeric.f_div;
  9992. import static org.jruby.util.Numeric.f_divmod;
  9993. import static org.jruby.util.Numeric.f_equal_p;
  9994. import static org.jruby.util.Numeric.f_exact_p;
  9995. import static org.jruby.util.Numeric.f_expt;
  9996. import static org.jruby.util.Numeric.f_gt_p;
  9997. import static org.jruby.util.Numeric.f_inspect;
  9998. import static org.jruby.util.Numeric.f_lcm;
  9999. import static org.jruby.util.Numeric.f_mul;
  10000. import static org.jruby.util.Numeric.f_negate;
  10001. import static org.jruby.util.Numeric.f_negative_p;
  10002. import static org.jruby.util.Numeric.f_numerator;
  10003. import static org.jruby.util.Numeric.f_one_p;
  10004. import static org.jruby.util.Numeric.f_polar;
  10005. import static org.jruby.util.Numeric.f_quo;
  10006. import static org.jruby.util.Numeric.f_scalar_p;
  10007. import static org.jruby.util.Numeric.f_sub;
  10008. import static org.jruby.util.Numeric.f_to_f;
  10009. import static org.jruby.util.Numeric.f_to_i;
  10010. import static org.jruby.util.Numeric.f_to_r;
  10011. import static org.jruby.util.Numeric.f_to_s;
  10012. import static org.jruby.util.Numeric.f_xor;
  10013. import static org.jruby.util.Numeric.f_zero_p;
  10014. import org.jruby.anno.JRubyClass;
  10015. import org.jruby.anno.JRubyMethod;
  10016. import org.jruby.runtime.Arity;
  10017. import org.jruby.runtime.ClassIndex;
  10018. import org.jruby.runtime.Frame;
  10019. import org.jruby.runtime.ObjectAllocator;
  10020. import org.jruby.runtime.ThreadContext;
  10021. import org.jruby.runtime.Visibility;
  10022. import org.jruby.runtime.builtin.IRubyObject;
  10023. import org.jruby.util.ByteList;
  10024. import org.jruby.util.Numeric;
  10025. /**
  10026. * 1.9 complex.c as of revision: 18876
  10027. */
  10028. @JRubyClass(name = "Complex", parent = "Numeric")
  10029. public class RubyComplex extends RubyNumeric {
  10030. public static RubyClass createComplexClass(Ruby runtime) {
  10031. RubyClass complexc = runtime.defineClass("Complex", runtime.getNumeric(), COMPLEX_ALLOCATOR); // because one can Complex.send(:allocate)
  10032. runtime.setComplex(complexc);
  10033. complexc.index = ClassIndex.COMPLEX;
  10034. complexc.kindOf = new RubyModule.KindOf() {
  10035. @Override
  10036. public boolean isKindOf(IRubyObject obj, RubyModule type) {
  10037. return obj instanceof RubyComplex;
  10038. }
  10039. };
  10040. ThreadContext context = runtime.getCurrentContext();
  10041. complexc.callMethod(context, "private_class_method", runtime.newSymbol("allocate"));
  10042. complexc.defineAnnotatedMethods(RubyComplex.class);
  10043. String[]undefined = {"<", "<=", "<=>", ">", ">=", "between?", "divmod",
  10044. "floor", "ceil", "modulo", "round", "step", "truncate"};
  10045. for (String undef : undefined) {
  10046. complexc.undefineMethod(undef);
  10047. }
  10048. complexc.defineConstant("I", RubyComplex.newComplexConvert(context, RubyFixnum.zero(runtime), RubyFixnum.one(runtime)));
  10049. return complexc;
  10050. }
  10051. private static ObjectAllocator COMPLEX_ALLOCATOR = new ObjectAllocator() {
  10052. public IRubyObject allocate(Ruby runtime, RubyClass klass) {
  10053. return new RubyComplex(runtime, klass, RubyFixnum.zero(runtime), RubyFixnum.zero(runtime));
  10054. }
  10055. };
  10056. /** internal
  10057. *
  10058. */
  10059. private RubyComplex(Ruby runtime, IRubyObject clazz, IRubyObject real, IRubyObject image) {
  10060. super(runtime, (RubyClass)clazz);
  10061. this.real = real;
  10062. this.image = image;
  10063. }
  10064. /** rb_complex_raw
  10065. *
  10066. */
  10067. static RubyComplex newComplexRaw(Ruby runtime, IRubyObject x, RubyObject y) {
  10068. return new RubyComplex(runtime, runtime.getComplex(), x, y);
  10069. }
  10070. /** rb_complex_raw1
  10071. *
  10072. */
  10073. static RubyComplex newComplexRaw(Ruby runtime, IRubyObject x) {
  10074. return new RubyComplex(runtime, runtime.getComplex(), x, RubyFixnum.zero(runtime));
  10075. }
  10076. /** rb_complex_new1
  10077. *
  10078. */
  10079. public static IRubyObject newComplexCanonicalize(ThreadContext context, IRubyObject x) {
  10080. return newComplexCanonicalize(context, x, RubyFixnum.zero(context.getRuntime()));
  10081. }
  10082. /** rb_complex_new
  10083. *
  10084. */
  10085. public static IRubyObject newComplexCanonicalize(ThreadContext context, IRubyObject x, IRubyObject y) {
  10086. return canonicalizeInternal(context, context.getRuntime().getComplex(), x, y);
  10087. }
  10088. /** rb_complex_polar
  10089. *
  10090. */
  10091. static IRubyObject newComplexPolar(ThreadContext context, IRubyObject x, IRubyObject y) {
  10092. return polar(context, context.getRuntime().getComplex(), x, y);
  10093. }
  10094. /** f_complex_new1
  10095. *
  10096. */
  10097. static IRubyObject newComplex(ThreadContext context, IRubyObject clazz, IRubyObject x) {
  10098. return newComplex(context, clazz, x, RubyFixnum.zero(context.getRuntime()));
  10099. }
  10100. /** f_complex_new2
  10101. *
  10102. */
  10103. static IRubyObject newComplex(ThreadContext context, IRubyObject clazz, IRubyObject x, IRubyObject y) {
  10104. assert !(x instanceof RubyComplex);
  10105. return canonicalizeInternal(context, clazz, x, y);
  10106. }
  10107. /** f_complex_new_bang2
  10108. *
  10109. */
  10110. static RubyComplex newComplexBang(ThreadContext context, IRubyObject clazz, IRubyObject x, IRubyObject y) {
  10111. assert x instanceof RubyComplex && y instanceof RubyComplex;
  10112. return new RubyComplex(context.getRuntime(), clazz, x, y);
  10113. }
  10114. /** f_complex_new_bang1
  10115. *
  10116. */
  10117. public static RubyComplex newComplexBang(ThreadContext context, IRubyObject clazz, IRubyObject x) {
  10118. assert x instanceof RubyComplex;
  10119. return newComplexBang(context, clazz, x, RubyFixnum.zero(context.getRuntime()));
  10120. }
  10121. private IRubyObject real;
  10122. private IRubyObject image;
  10123. IRubyObject getImage() {
  10124. return image;
  10125. }
  10126. IRubyObject getReal() {
  10127. return real;
  10128. }
  10129. /** m_cos
  10130. *
  10131. */
  10132. private static IRubyObject m_cos(ThreadContext context, IRubyObject x) {
  10133. if (f_scalar_p(context, x).isTrue()) return RubyMath.cos(x, x);
  10134. RubyComplex complex = (RubyComplex)x;
  10135. return newComplex(context, context.getRuntime().getComplex(),
  10136. f_mul(context, RubyMath.cos(x, complex.real), RubyMath.cosh(x, complex.image)),
  10137. f_mul(context, f_negate(context, RubyMath.sin(x, complex.real)), RubyMath.sinh(x, complex.image)));
  10138. }
  10139. /** m_sin
  10140. *
  10141. */
  10142. private static IRubyObject m_sin(ThreadContext context, IRubyObject x) {
  10143. if (f_scalar_p(context, x).isTrue()) return RubyMath.sin(x, x);
  10144. RubyComplex complex = (RubyComplex)x;
  10145. return newComplex(context, context.getRuntime().getComplex(),
  10146. f_mul(context, RubyMath.sin(x, complex.real), RubyMath.cosh(x, complex.image)),
  10147. f_mul(context, RubyMath.cos(x, complex.real), RubyMath.sinh(x, complex.image)));
  10148. }
  10149. /** m_sqrt
  10150. *
  10151. */
  10152. private static IRubyObject m_sqrt(ThreadContext context, IRubyObject x) {
  10153. if (f_scalar_p(context, x).isTrue()) {
  10154. if (!f_negative_p(context, x)) return RubyMath.sqrt(x, x);
  10155. return newComplex(context, context.getRuntime().getComplex(),
  10156. RubyFixnum.zero(context.getRuntime()),
  10157. RubyMath.sqrt(x, f_negate(context, x)));
  10158. } else {
  10159. RubyComplex complex = (RubyComplex)x;
  10160. if (f_negative_p(context, complex.image)) {
  10161. return f_conjugate(context, m_sqrt(context, f_conjugate(context, x)));
  10162. } else {
  10163. IRubyObject a = f_abs(context, x);
  10164. IRubyObject two = RubyFixnum.two(context.getRuntime());
  10165. return newComplex(context, context.getRuntime().getComplex(),
  10166. RubyMath.sqrt(x, f_div(context, f_add(context, a, complex.real), two)),
  10167. RubyMath.sqrt(x, f_div(context, f_sub(context, a, complex.real), two)));
  10168. }
  10169. }
  10170. }
  10171. /** nucomp_s_new_bang
  10172. *
  10173. */
  10174. @Deprecated
  10175. public static IRubyObject newInstanceBang(ThreadContext context, IRubyObject recv, IRubyObject[]args) {
  10176. switch (args.length) {
  10177. case 1: return newInstanceBang(context, recv, args[0]);
  10178. case 2: return newInstanceBang(context, recv, args[0], args[1]);
  10179. }
  10180. Arity.raiseArgumentError(context.getRuntime(), args.length, 1, 1);
  10181. return null;
  10182. }
  10183. @JRubyMethod(name = "new!", meta = true, visibility = Visibility.PRIVATE)
  10184. public static IRubyObject newInstanceBang(ThreadContext context, IRubyObject recv, IRubyObject real) {
  10185. if (!(real instanceof RubyNumeric)) real = f_to_i(context, real);
  10186. return new RubyComplex(context.getRuntime(), recv, real, RubyFixnum.zero(context.getRuntime()));
  10187. }
  10188. @JRubyMethod(name = "new!", meta = true, visibility = Visibility.PRIVATE)
  10189. public static IRubyObject newInstanceBang(ThreadContext context, IRubyObject recv, IRubyObject real, IRubyObject image) {
  10190. if (!(real instanceof RubyNumeric)) real = f_to_i(context, real);
  10191. if (!(image instanceof RubyNumeric)) image = f_to_i(context, image);
  10192. return new RubyComplex(context.getRuntime(), recv, real, image);
  10193. }
  10194. /** nucomp_real_check (might go to bimorphic)
  10195. *
  10196. */
  10197. private static void realCheck(ThreadContext context, IRubyObject num) {
  10198. switch (num.getMetaClass().index) {
  10199. case ClassIndex.FIXNUM:
  10200. case ClassIndex.BIGNUM:
  10201. case ClassIndex.FLOAT:
  10202. case ClassIndex.RATIONAL:
  10203. break;
  10204. default:
  10205. if (!(num instanceof RubyNumeric ) || !f_scalar_p(context, num).isTrue()) {
  10206. throw context.getRuntime().newArgumentError("not a real");
  10207. }
  10208. }
  10209. }
  10210. /** nucomp_s_canonicalize_internal
  10211. *
  10212. */
  10213. private static final boolean CL_CANNON = true;
  10214. private static IRubyObject canonicalizeInternal(ThreadContext context, IRubyObject clazz, IRubyObject real, IRubyObject image) {
  10215. if (f_zero_p(context, image) &&
  10216. ((RubyModule)clazz).fastHasConstant("Unify") &&
  10217. (!CL_CANNON ||
  10218. (!(real instanceof RubyFloat) &&
  10219. !(image instanceof RubyFloat)))) {
  10220. return real;
  10221. } else if (f_scalar_p(context, real).isTrue() &&
  10222. f_scalar_p(context, image).isTrue()) {
  10223. return new RubyComplex(context.getRuntime(), clazz, real, image);
  10224. } else if (f_scalar_p(context, real).isTrue()) {
  10225. RubyComplex complex = (RubyComplex)image;
  10226. return new RubyComplex(context.getRuntime(), clazz,
  10227. f_sub(context, real, complex.image),
  10228. f_add(context, RubyFixnum.zero(context.getRuntime()), complex.real));
  10229. } else if (f_scalar_p(context, image).isTrue()) {
  10230. RubyComplex complex = (RubyComplex)real;
  10231. return new RubyComplex(context.getRuntime(), clazz,
  10232. complex.real,
  10233. f_add(context, complex.image, image));
  10234. } else {
  10235. RubyComplex complex1 = (RubyComplex)real;
  10236. RubyComplex complex2 = (RubyComplex)image;
  10237. return new RubyComplex(context.getRuntime(), clazz,
  10238. f_sub(context, complex1.real, complex2.image),
  10239. f_add(context, complex1.image, complex2.real));
  10240. }
  10241. }
  10242. /** nucomp_s_new
  10243. *
  10244. */
  10245. @Deprecated
  10246. public static IRubyObject newInstance(ThreadContext context, IRubyObject recv, IRubyObject[]args) {
  10247. switch (args.length) {
  10248. case 1: return newInstance(context, recv, args[0]);
  10249. case 2: return newInstance(context, recv, args[0], args[1]);
  10250. }
  10251. Arity.raiseArgumentError(context.getRuntime(), args.length, 1, 1);
  10252. return null;
  10253. }
  10254. @JRubyMethod(name = {"new", "rect", "rectangular"}, meta = true)
  10255. public static IRubyObject newInstance(ThreadContext context, IRubyObject recv, IRubyObject real) {
  10256. realCheck(context, real);
  10257. return canonicalizeInternal(context, recv, real, RubyFixnum.zero(context.getRuntime()));
  10258. }
  10259. @JRubyMethod(name = {"new", "rect", "rectangular"}, meta = true)
  10260. public static IRubyObject newInstance(ThreadContext context, IRubyObject recv, IRubyObject real, IRubyObject image) {
  10261. realCheck(context, real);
  10262. realCheck(context, image);
  10263. return canonicalizeInternal(context, recv, real, image);
  10264. }
  10265. /** f_complex_polar
  10266. *
  10267. */
  10268. private static IRubyObject f_complex_polar(ThreadContext context, IRubyObject clazz, IRubyObject x, IRubyObject y) {
  10269. assert !(x instanceof RubyComplex) && !(y instanceof RubyComplex);
  10270. return canonicalizeInternal(context, clazz,
  10271. f_mul(context, x, m_cos(context, y)),
  10272. f_mul(context, x, m_sin(context, y)));
  10273. }
  10274. /** nucomp_s_polar
  10275. *
  10276. */
  10277. @JRubyMethod(name = "polar", meta = true)
  10278. public static IRubyObject polar(ThreadContext context, IRubyObject clazz, IRubyObject abs, IRubyObject arg) {
  10279. return f_complex_polar(context, clazz, abs, arg);
  10280. }
  10281. /** rb_Complex1
  10282. *
  10283. */
  10284. public static IRubyObject newComplexConvert(ThreadContext context, IRubyObject x) {
  10285. return newComplexConvert(context, x, RubyFixnum.zero(context.getRuntime()));
  10286. }
  10287. /** rb_Complex/rb_Complex2
  10288. *
  10289. */
  10290. public static IRubyObject newComplexConvert(ThreadContext context, IRubyObject x, IRubyObject y) {
  10291. return convert(context, context.getRuntime().getComplex(), x, y);
  10292. }
  10293. @Deprecated
  10294. public static IRubyObject convert(ThreadContext context, IRubyObject clazz, IRubyObject[]args) {
  10295. switch (args.length) {
  10296. case 0: return convert(context, clazz);
  10297. case 1: return convert(context, clazz, args[0]);
  10298. case 2: return convert(context, clazz, args[0], args[1]);
  10299. }
  10300. Arity.raiseArgumentError(context.getRuntime(), args.length, 0, 2);
  10301. return null;
  10302. }
  10303. /** nucomp_s_convert
  10304. *
  10305. */
  10306. @JRubyMethod(name = "convert", meta = true, visibility = Visibility.PRIVATE)
  10307. public static IRubyObject convert(ThreadContext context, IRubyObject recv) {
  10308. IRubyObject nil = context.getRuntime().getNil();
  10309. return convertCommon(context, recv, nil, nil);
  10310. }
  10311. /** nucomp_s_convert
  10312. *
  10313. */
  10314. @JRubyMethod(name = "convert", meta = true, visibility = Visibility.PRIVATE)
  10315. public static IRubyObject convert(ThreadContext context, IRubyObject recv, IRubyObject a1) {
  10316. return convertCommon(context, recv, a1, context.getRuntime().getNil());
  10317. }
  10318. /** nucomp_s_convert
  10319. *
  10320. */
  10321. @JRubyMethod(name = "convert", meta = true, visibility = Visibility.PRIVATE)
  10322. public static IRubyObject convert(ThreadContext context, IRubyObject recv, IRubyObject a1, IRubyObject a2) {
  10323. return convertCommon(context, recv, a1, a2);
  10324. }
  10325. private static IRubyObject convertCommon(ThreadContext context, IRubyObject recv, IRubyObject a1, IRubyObject a2) {
  10326. Frame frame = context.getCurrentFrame();
  10327. IRubyObject backref = frame.getBackRef();
  10328. if (backref != null && backref instanceof RubyMatchData) ((RubyMatchData)backref).use();
  10329. if (a1 instanceof RubyString) a1 = str_to_c_strict(context, a1);
  10330. if (a2 instanceof RubyString) a2 = str_to_c_strict(context, a2);
  10331. frame.setBackRef(backref);
  10332. if (a1 instanceof RubyComplex) {
  10333. RubyComplex a1Complex = (RubyComplex)a1;
  10334. if (!(a1Complex.image instanceof RubyFloat) && f_zero_p(context, a1Complex.image)) {
  10335. a1 = a1Complex.real;
  10336. }
  10337. }
  10338. if (a2 instanceof RubyComplex) {
  10339. RubyComplex a2Complex = (RubyComplex)a2;
  10340. if (!(a2Complex.image instanceof RubyFloat) && f_zero_p(context, a2Complex.image)) {
  10341. a2 = a2Complex.real;
  10342. }
  10343. }
  10344. if (a1 instanceof RubyComplex) {
  10345. if (a2.isNil() || f_zero_p(context, a2)) return a1;
  10346. }
  10347. return a2.isNil() ? newInstance(context, recv, a1) : newInstance(context, recv, a1, a2);
  10348. }
  10349. /** nucomp_real
  10350. *
  10351. */
  10352. @JRubyMethod(name = "real")
  10353. public IRubyObject real() {
  10354. return real;
  10355. }
  10356. /** nucomp_image
  10357. *
  10358. */
  10359. @JRubyMethod(name = {"image", "imag"})
  10360. public IRubyObject image() {
  10361. return image;
  10362. }
  10363. /** nucomp_add
  10364. *
  10365. */
  10366. @JRubyMethod(name = "+")
  10367. public IRubyObject op_add(ThreadContext context, IRubyObject other) {
  10368. if (other instanceof RubyComplex) {
  10369. RubyComplex otherComplex = (RubyComplex)other;
  10370. return newComplex(context, getMetaClass(),
  10371. f_add(context, real, otherComplex.real),
  10372. f_add(context, image, otherComplex.image));
  10373. } else if (other instanceof RubyNumeric && f_scalar_p(context, other).isTrue()) {
  10374. return newComplex(context, getMetaClass(), f_add(context, real, other), image);
  10375. }
  10376. return coerceBin(context, "+", other);
  10377. }
  10378. /** nucomp_sub
  10379. *
  10380. */
  10381. @JRubyMethod(name = "-")
  10382. public IRubyObject op_sub(ThreadContext context, IRubyObject other) {
  10383. if (other instanceof RubyComplex) {
  10384. RubyComplex otherComplex = (RubyComplex)other;
  10385. return newComplex(context, getMetaClass(),
  10386. f_sub(context, real, otherComplex.real),
  10387. f_sub(context, image, otherComplex.image));
  10388. } else if (other instanceof RubyNumeric && f_scalar_p(context, other).isTrue()) {
  10389. return newComplex(context, getMetaClass(), f_sub(context, real, other), image);
  10390. }
  10391. return coerceBin(context, "-", other);
  10392. }
  10393. /** nucomp_mul
  10394. *
  10395. */
  10396. @JRubyMethod(name = "*")
  10397. public IRubyObject op_mul(ThreadContext context, IRubyObject other) {
  10398. if (other instanceof RubyComplex) {
  10399. RubyComplex otherComplex = (RubyComplex)other;
  10400. IRubyObject realp = f_sub(context,
  10401. f_mul(context, real, otherComplex.real),
  10402. f_mul(context, image, otherComplex.image));
  10403. IRubyObject imagep = f_add(context,
  10404. f_mul(context, real, otherComplex.image),
  10405. f_mul(context, image, otherComplex.real));
  10406. return newComplex(context, getMetaClass(), realp, imagep);
  10407. } else if (other instanceof RubyNumeric && f_scalar_p(context, other).isTrue()) {
  10408. return newComplex(context, getMetaClass(),
  10409. f_mul(context, real, other),
  10410. f_mul(context, image, other));
  10411. }
  10412. return coerceBin(context, "*", other);
  10413. }
  10414. /** nucomp_div
  10415. *
  10416. */
  10417. @JRubyMethod(name = "/")
  10418. public IRubyObject op_div(ThreadContext context, IRubyObject other) {
  10419. if (other instanceof RubyComplex) {
  10420. RubyComplex otherComplex = (RubyComplex)other;
  10421. if (real instanceof RubyFloat || image instanceof RubyFloat ||
  10422. otherComplex.real instanceof RubyFloat || otherComplex.image instanceof RubyFloat) {
  10423. IRubyObject magn = RubyMath.hypot(this, otherComplex.real, otherComplex.image);
  10424. IRubyObject tmp = newComplexBang(context, getMetaClass(),
  10425. f_quo(context, otherComplex.real, magn),
  10426. f_quo(context, otherComplex.image, magn));
  10427. return f_quo(context, f_mul(context, this, f_conjugate(context, tmp)), magn);
  10428. }
  10429. return f_quo(context, f_mul(context, this, f_conjugate(context, other)), f_abs2(context, other));
  10430. } else if (other instanceof RubyNumeric && f_scalar_p(context, other).isTrue()) {
  10431. return newComplex(context, getMetaClass(),
  10432. f_quo(context, real, other),
  10433. f_quo(context, image, other));
  10434. }
  10435. return coerceBin(context, "/", other);
  10436. }
  10437. /** nucomp_fdiv / nucomp_quo
  10438. *
  10439. */
  10440. @JRubyMethod(name = {"fdiv", "quo"})
  10441. public IRubyObject fdiv(ThreadContext context, IRubyObject other) {
  10442. IRubyObject complex = newComplex(context, getMetaClass(),
  10443. f_to_f(context, real),
  10444. f_to_f(context, image));
  10445. return f_div(context, complex, other);
  10446. }
  10447. /** nucomp_expt
  10448. *
  10449. */
  10450. @JRubyMethod(name = "**")
  10451. public IRubyObject op_expt(ThreadContext context, IRubyObject other) {
  10452. if (f_zero_p(context, other)) {
  10453. return newComplexBang(context, getMetaClass(), RubyFixnum.one(context.getRuntime()));
  10454. } else if (other instanceof RubyRational && f_one_p(context, f_denominator(context, other))) {
  10455. other = f_numerator(context, other);
  10456. }
  10457. if (other instanceof RubyComplex) {
  10458. RubyArray a = f_polar(context, this).convertToArray();
  10459. IRubyObject r = a.eltInternal(0);
  10460. IRubyObject theta = a.eltInternal(1);
  10461. RubyComplex otherComplex = (RubyComplex)other;
  10462. IRubyObject nr = RubyMath.exp(this, f_sub(context,
  10463. f_mul(context, otherComplex.real, RubyMath.log(this, r)),
  10464. f_mul(context, otherComplex.image, theta)));
  10465. IRubyObject ntheta = f_add(context,
  10466. f_mul(context, theta, otherComplex.real),
  10467. f_mul(context, otherComplex.image, RubyMath.log(this, r)));
  10468. return polar(context, getMetaClass(), nr, ntheta);
  10469. } else if (other instanceof RubyInteger) {
  10470. IRubyObject one = RubyFixnum.one(context.getRuntime());
  10471. if (f_gt_p(context, other, RubyFixnum.zero(context.getRuntime())).isTrue()) {
  10472. IRubyObject x = this;
  10473. IRubyObject z = x;
  10474. IRubyObject n = f_sub(context, other, one);
  10475. IRubyObject two = RubyFixnum.two(context.getRuntime());
  10476. while (!f_zero_p(context, n)) {
  10477. RubyArray a = f_divmod(context, n, two).convertToArray();
  10478. while (f_zero_p(context, a.eltInternal(1))) {
  10479. RubyComplex xComplex = (RubyComplex)x;
  10480. x = newComplex(context, getMetaClass(),
  10481. f_sub(context, f_mul(context, xComplex.real, xComplex.real),
  10482. f_mul(context, xComplex.image, xComplex.image)),
  10483. f_mul(context, f_mul(context, two, xComplex.real), xComplex.image));
  10484. n = a.eltInternal(0);
  10485. a = f_divmod(context, n, two).convertToArray();
  10486. }
  10487. z = f_mul(context, z, x);
  10488. n = f_sub(context, n, one);
  10489. }
  10490. return z;
  10491. }
  10492. return f_expt(context, f_div(context, f_to_r(context, one), this), f_negate(context, other));
  10493. } else if (other instanceof RubyNumeric && f_scalar_p(context, other).isTrue()) {
  10494. RubyArray a = f_polar(context, this).convertToArray();
  10495. IRubyObject r = a.eltInternal(0);
  10496. IRubyObject theta = a.eltInternal(1);
  10497. return f_complex_polar(context, getMetaClass(), f_expt(context, r, other), f_mul(context, theta, other));
  10498. }
  10499. return coerceBin(context, "**", other);
  10500. }
  10501. /** nucomp_equal_p
  10502. *
  10503. */
  10504. @JRubyMethod(name = "==")
  10505. public IRubyObject op_equal(ThreadContext context, IRubyObject other) {
  10506. if (other instanceof RubyComplex) {
  10507. RubyComplex otherComplex = (RubyComplex)other;
  10508. if (f_equal_p(context, real, otherComplex.real) && f_equal_p(context, image, otherComplex.image)) return context.getRuntime().getTrue();
  10509. return context.getRuntime().getFalse();
  10510. } else if (other instanceof RubyNumeric && f_scalar_p(context, other).isTrue()) {
  10511. if (f_equal_p(context, real, other) && f_zero_p(context, image)) return context.getRuntime().getTrue();
  10512. return context.getRuntime().getFalse();
  10513. }
  10514. return f_equal_p(context, other, this) ? context.getRuntime().getTrue() : context.getRuntime().getFalse();
  10515. }
  10516. /** nucomp_coerce
  10517. *
  10518. */
  10519. @JRubyMethod(name = "coerce")
  10520. public IRubyObject coerce(ThreadContext context, IRubyObject other) {
  10521. if (other instanceof RubyNumeric && f_scalar_p(context, other).isTrue()) {
  10522. return context.getRuntime().newArray(newComplexBang(context, getMetaClass(), other), this);
  10523. }
  10524. throw context.getRuntime().newTypeError(other.getMetaClass().getName() + " can't be coerced into " + getMetaClass().getName());
  10525. }
  10526. /** nucomp_abs
  10527. *
  10528. */
  10529. @JRubyMethod(name = {"abs", "magnitude"})
  10530. public IRubyObject abs(ThreadContext context) {
  10531. return RubyMath.hypot(this, real, image);
  10532. }
  10533. /** nucomp_abs2
  10534. *
  10535. */
  10536. @JRubyMethod(name = "abs2")
  10537. public IRubyObject abs2(ThreadContext context) {
  10538. return f_add(context,
  10539. f_mul(context, real, real),
  10540. f_mul(context, image, image));
  10541. }
  10542. /** nucomp_arg
  10543. *
  10544. */
  10545. @JRubyMethod(name = {"arg", "angle"})
  10546. public IRubyObject arg(ThreadContext context) {
  10547. return RubyMath.atan2(this, image, real);
  10548. }
  10549. /** nucomp_polar
  10550. *
  10551. */
  10552. @JRubyMethod(name = "polar")
  10553. public IRubyObject polar(ThreadContext context) {
  10554. return context.getRuntime().newArray(f_abs(context, this), f_arg(context, this));
  10555. }
  10556. /** nucomp_conjugate
  10557. *
  10558. */
  10559. @JRubyMethod(name = {"conjugate", "conj", "~"})
  10560. public IRubyObject conjugate(ThreadContext context) {
  10561. return newComplex(context, getMetaClass(), real, f_negate(context, image));
  10562. }
  10563. /** nucomp_real_p
  10564. *
  10565. */
  10566. //@JRubyMethod(name = "real?")
  10567. public IRubyObject real_p(ThreadContext context) {
  10568. return context.getRuntime().getFalse();
  10569. }
  10570. /** nucomp_complex_p
  10571. *
  10572. */
  10573. // @JRubyMethod(name = "complex?")
  10574. public IRubyObject complex_p(ThreadContext context) {
  10575. return context.getRuntime().getTrue();
  10576. }
  10577. /** nucomp_exact_p
  10578. *
  10579. */
  10580. // @JRubyMethod(name = "exact?")
  10581. public IRubyObject exact_p(ThreadContext context) {
  10582. return (f_exact_p(context, real).isTrue() && f_exact_p(context, image).isTrue()) ? context.getRuntime().getTrue() : context.getRuntime().getFalse();
  10583. }
  10584. /** nucomp_exact_p
  10585. *
  10586. */
  10587. // @JRubyMethod(name = "inexact?")
  10588. public IRubyObject inexact_p(ThreadContext context) {
  10589. return exact_p(context).isTrue() ? context.getRuntime().getFalse() : context.getRuntime().getTrue();
  10590. }
  10591. /** nucomp_denominator
  10592. *
  10593. */
  10594. @JRubyMethod(name = "denominator")
  10595. public IRubyObject demoninator(ThreadContext context) {
  10596. return f_lcm(context, f_denominator(context, real), f_denominator(context, image));
  10597. }
  10598. /** nucomp_numerator
  10599. *
  10600. */
  10601. @JRubyMethod(name = "numerator")
  10602. public IRubyObject numerator(ThreadContext context) {
  10603. IRubyObject cd = callMethod(context, "denominator");
  10604. return newComplex(context, getMetaClass(),
  10605. f_mul(context,
  10606. f_numerator(context, real),
  10607. f_div(context, cd, f_denominator(context, real))),
  10608. f_mul(context,
  10609. f_numerator(context, image),
  10610. f_div(context, cd, f_denominator(context, image))));
  10611. }
  10612. /** nucomp_hash
  10613. *
  10614. */
  10615. @JRubyMethod(name = "hash")
  10616. public IRubyObject hash(ThreadContext context) {
  10617. return f_xor(context, real, image);
  10618. }
  10619. /** f_signbit
  10620. *
  10621. */
  10622. private static boolean signbit(ThreadContext context, IRubyObject x) {
  10623. if (x instanceof RubyFloat) {
  10624. return Double.doubleToLongBits(((RubyFloat)x).getDoubleValue()) < 0;
  10625. }
  10626. return f_negative_p(context, x);
  10627. }
  10628. /** f_tpositive_p
  10629. *
  10630. */
  10631. private static boolean tpositive_p(ThreadContext context, IRubyObject x) {
  10632. return !signbit(context, x);
  10633. }
  10634. /** nucomp_to_s
  10635. *
  10636. */
  10637. @JRubyMethod(name = "to_s")
  10638. public IRubyObject to_s(ThreadContext context) {
  10639. boolean impos = tpositive_p(context, image);
  10640. RubyString str = f_to_s(context, real).convertToString();
  10641. str.cat(impos ? (byte)'+' : (byte)'-');
  10642. str.cat(f_to_s(context, f_abs(context, image)).convertToString().getByteList());
  10643. str.cat((byte)'i');
  10644. return str;
  10645. }
  10646. /** nucomp_inspect
  10647. *
  10648. */
  10649. @JRubyMethod(name = "inspect")
  10650. public IRubyObject inspect(ThreadContext context) {
  10651. boolean impos = tpositive_p(context, image);
  10652. RubyString str = context.getRuntime().newString();
  10653. str.cat((byte)'(');
  10654. str.cat(f_inspect(context, real).convertToString().getByteList());
  10655. str.cat(impos ? (byte)'+' : (byte)'-');
  10656. str.cat(f_inspect(context, f_abs(context, image)).convertToString().getByteList());
  10657. str.cat((byte)'i');
  10658. str.cat((byte)')');
  10659. return str;
  10660. }
  10661. /** nucomp_marshal_dump
  10662. *
  10663. */
  10664. @JRubyMethod(name = "marshal_dump")
  10665. public IRubyObject marshal_dump(ThreadContext context) {
  10666. return context.getRuntime().newArray(real, image);
  10667. }
  10668. /** nucomp_marshal_load
  10669. *
  10670. */
  10671. @JRubyMethod(name = "marshal_load")
  10672. public IRubyObject marshal_load(ThreadContext context, IRubyObject arg) {
  10673. RubyArray a = arg.convertToArray();
  10674. real = a.size() > 0 ? a.eltInternal(0) : context.getRuntime().getNil();
  10675. image = a.size() > 1 ? a.eltInternal(1) : context.getRuntime().getNil();
  10676. return this;
  10677. }
  10678. /** nucomp_scalar_p
  10679. *
  10680. */
  10681. @JRubyMethod(name = "scalar?")
  10682. public IRubyObject scalar_p(ThreadContext context) {
  10683. return context.getRuntime().getFalse();
  10684. }
  10685. /** nucomp_to_i
  10686. *
  10687. */
  10688. @JRubyMethod(name = "to_i")
  10689. public IRubyObject to_i(ThreadContext context) {
  10690. if (image instanceof RubyFloat || !f_zero_p(context, image)) {
  10691. throw context.getRuntime().newRangeError("can't convert " + f_to_s(context, this).convertToString() + " into Integer");
  10692. }
  10693. return f_to_i(context, real);
  10694. }
  10695. /** nucomp_to_f
  10696. *
  10697. */
  10698. @JRubyMethod(name = "to_f")
  10699. public IRubyObject to_f(ThreadContext context) {
  10700. if (image instanceof RubyFloat || !f_zero_p(context, image)) {
  10701. throw context.getRuntime().newRangeError("can't convert " + f_to_s(context, this).convertToString() + " into Float");
  10702. }
  10703. return f_to_f(context, real);
  10704. }
  10705. /** nucomp_to_f
  10706. *
  10707. */
  10708. @JRubyMethod(name = "to_r")
  10709. public IRubyObject to_r(ThreadContext context) {
  10710. if (image instanceof RubyFloat || !f_zero_p(context, image)) {
  10711. throw context.getRuntime().newRangeError("can't convert " + f_to_s(context, this).convertToString() + " into Rational");
  10712. }
  10713. return f_to_r(context, real);
  10714. }
  10715. static RubyArray str_to_c_internal(ThreadContext context, IRubyObject recv) {
  10716. RubyString s = recv.callMethod(context, "strip").convertToString();
  10717. ByteList bytes = s.getByteList();
  10718. Ruby runtime = context.getRuntime();
  10719. if (bytes.realSize == 0) return runtime.newArray(runtime.getNil(), recv);
  10720. IRubyObject sr, si, re;
  10721. sr = si = re = runtime.getNil();
  10722. boolean po = false;
  10723. IRubyObject m = RubyRegexp.newRegexp(runtime, Numeric.ComplexPatterns.comp_pat0).callMethod(context, "match", s);
  10724. if (!m.isNil()) {
  10725. sr = m.callMethod(context, "[]", RubyFixnum.one(runtime));
  10726. si = m.callMethod(context, "[]", RubyFixnum.two(runtime));
  10727. re = m.callMethod(context, "post_match");
  10728. po = true;
  10729. }
  10730. if (m.isNil()) {
  10731. m = RubyRegexp.newRegexp(runtime, Numeric.ComplexPatterns.comp_pat1).callMethod(context, "match", s);
  10732. if (!m.isNil()) {
  10733. sr = runtime.getNil();
  10734. si = m.callMethod(context, "[]", RubyFixnum.one(runtime));
  10735. if (si.isNil()) si = runtime.newString();
  10736. IRubyObject t = m.callMethod(context, "[]", RubyFixnum.two(runtime));
  10737. if (t.isNil()) t = runtime.newString(new ByteList(new byte[]{'1'}));
  10738. si.convertToString().cat(t.convertToString().getByteList());
  10739. re = m.callMethod(context, "post_match");
  10740. po = false;
  10741. }
  10742. }
  10743. if (m.isNil()) {
  10744. m = RubyRegexp.newRegexp(runtime, Numeric.ComplexPatterns.comp_pat2).callMethod(context, "match", s);
  10745. if (m.isNil()) return runtime.newArray(runtime.getNil(), recv);
  10746. sr = m.callMethod(context, "[]", RubyFixnum.one(runtime));
  10747. if (m.callMethod(context, "[]", RubyFixnum.two(runtime)).isNil()) {
  10748. si = runtime.getNil();
  10749. } else {
  10750. si = m.callMethod(context, "[]", RubyFixnum.three(runtime));
  10751. IRubyObject t = m.callMethod(context, "[]", RubyFixnum.four(runtime));
  10752. if (t.isNil()) t = runtime.newString(new ByteList(new byte[]{'1'}));
  10753. si.convertToString().cat(t.convertToString().getByteList());
  10754. }
  10755. re = m.callMethod(context, "post_match");
  10756. po = false;
  10757. }
  10758. IRubyObject r = RubyFixnum.zero(runtime);
  10759. IRubyObject i = r;
  10760. if (!sr.isNil()) {
  10761. if (sr.callMethod(context, "include?", runtime.newString(new ByteList(new byte[]{'/'}))).isTrue()) {
  10762. r = f_to_r(context, sr);
  10763. } else if (f_gt_p(context, sr.callMethod(context, "count", runtime.newString(".eE")), RubyFixnum.zero(runtime)).isTrue()) {
  10764. r = f_to_f(context, sr);
  10765. } else {
  10766. r = f_to_i(context, sr);
  10767. }
  10768. }
  10769. if (!si.isNil()) {
  10770. if (si.callMethod(context, "include?", runtime.newString(new ByteList(new byte[]{'/'}))).isTrue()) {
  10771. i = f_to_r(context, si);
  10772. } else if (f_gt_p(context, si.callMethod(context, "count", runtime.newString(".eE")), RubyFixnum.zero(runtime)).isTrue()) {
  10773. i = f_to_f(context, si);
  10774. } else {
  10775. i = f_to_i(context, si);
  10776. }
  10777. }
  10778. return runtime.newArray(po ? newComplexPolar(context, r, i) : newComplexCanonicalize(context, r, i), re);
  10779. }
  10780. private static IRubyObject str_to_c_strict(ThreadContext context, IRubyObject recv) {
  10781. RubyArray a = str_to_c_internal(context, recv);
  10782. if (a.eltInternal(0).isNil() || a.eltInternal(1).convertToString().getByteList().length() > 0) {
  10783. IRubyObject s = recv.callMethod(context, "inspect");
  10784. throw context.getRuntime().newArgumentError("invalid value for Complex: " + s.convertToString());
  10785. }
  10786. return a.eltInternal(0);
  10787. }
  10788. }
  10789. /***** BEGIN LICENSE BLOCK *****
  10790. * Version: CPL 1.0/GPL 2.0/LGPL 2.1
  10791. *
  10792. * The contents of this file are subject to the Common Public
  10793. * License Version 1.0 (the "License"); you may not use this file
  10794. * except in compliance with the License. You may obtain a copy of
  10795. * the License at http://www.eclipse.org/legal/cpl-v10.html
  10796. *
  10797. * Software distributed under the License is distributed on an "AS
  10798. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  10799. * implied. See the License for the specific language governing
  10800. * rights and limitations under the License.
  10801. *
  10802. * Copyright (C) 2007 Ola Bini <ola@ologix.com>
  10803. *
  10804. * Alternatively, the contents of this file may be used under the terms of
  10805. * either of the GNU General Public License Version 2 or later (the "GPL"),
  10806. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  10807. * in which case the provisions of the GPL or the LGPL are applicable instead
  10808. * of those above. If you wish to allow use of your version of this file only
  10809. * under the terms of either the GPL or the LGPL, and not to allow others to
  10810. * use your version of this file under the terms of the CPL, indicate your
  10811. * decision by deleting the provisions above and replace them with the notice
  10812. * and other provisions required by the GPL or the LGPL. If you do not delete
  10813. * the provisions above, a recipient may use your version of this file under
  10814. * the terms of any one of the CPL, the GPL or the LGPL.
  10815. ***** END LICENSE BLOCK *****/
  10816. package org.jruby;
  10817. import org.jruby.anno.JRubyMethod;
  10818. import org.jruby.anno.JRubyClass;
  10819. import org.jruby.runtime.Block;
  10820. import org.jruby.runtime.builtin.IRubyObject;
  10821. /**
  10822. * Placeholder until/if we can support this
  10823. *
  10824. * @author <a href="mailto:ola.bini@ki.se">Ola Bini</a>
  10825. */
  10826. @JRubyClass(name="Continuation")
  10827. public class RubyContinuation {
  10828. public static void createContinuation(Ruby runtime) {
  10829. RubyClass cContinuation = runtime.defineClass("Continuation",runtime.getObject(),runtime.getObject().getAllocator());
  10830. cContinuation.defineAnnotatedMethods(RubyContinuation.class);
  10831. runtime.setContinuation(cContinuation);
  10832. }
  10833. @JRubyMethod(name = {"call", "[]"}, rest = true, frame = true)
  10834. public static IRubyObject call(IRubyObject recv, IRubyObject[] args, Block unusedBlock) {
  10835. throw recv.getRuntime().newNotImplementedError("Continuations are not implemented in JRuby and will not work");
  10836. }
  10837. }// RubyContinuation
  10838. /*
  10839. ***** BEGIN LICENSE BLOCK *****
  10840. * Version: CPL 1.0/GPL 2.0/LGPL 2.1
  10841. *
  10842. * The contents of this file are subject to the Common Public
  10843. * License Version 1.0 (the "License"); you may not use this file
  10844. * except in compliance with the License. You may obtain a copy of
  10845. * the License at http://www.eclipse.org/legal/cpl-v10.html
  10846. *
  10847. * Software distributed under the License is distributed on an "AS
  10848. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  10849. * implied. See the License for the specific language governing
  10850. * rights and limitations under the License.
  10851. *
  10852. * Copyright (C) 2006, 2007 Ola Bini <ola@ologix.com>
  10853. * Copyright (C) 2007 Nick Sieger <nicksieger@gmail.com>
  10854. * Copyright (C) 2008 Vladimir Sizikov <vsizikov@gmail.com>
  10855. *
  10856. * Alternatively, the contents of this file may be used under the terms of
  10857. * either of the GNU General Public License Version 2 or later (the "GPL"),
  10858. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  10859. * in which case the provisions of the GPL or the LGPL are applicable instead
  10860. * of those above. If you wish to allow use of your version of this file only
  10861. * under the terms of either the GPL or the LGPL, and not to allow others to
  10862. * use your version of this file under the terms of the CPL, indicate your
  10863. * decision by deleting the provisions above and replace them with the notice
  10864. * and other provisions required by the GPL or the LGPL. If you do not delete
  10865. * the provisions above, a recipient may use your version of this file under
  10866. * the terms of any one of the CPL, the GPL or the LGPL.
  10867. ***** END LICENSE BLOCK *****/
  10868. package org.jruby;
  10869. import java.security.Provider;
  10870. import java.security.MessageDigest;
  10871. import java.security.NoSuchAlgorithmException;
  10872. import org.jruby.anno.JRubyMethod;
  10873. import org.jruby.anno.JRubyModule;
  10874. import org.jruby.anno.JRubyClass;
  10875. import org.jruby.runtime.Arity;
  10876. import org.jruby.runtime.Block;
  10877. import org.jruby.runtime.ObjectAllocator;
  10878. import org.jruby.runtime.builtin.IRubyObject;
  10879. import org.jruby.runtime.callback.Callback;
  10880. import org.jruby.util.ByteList;
  10881. /**
  10882. * @author <a href="mailto:ola.bini@ki.se">Ola Bini</a>
  10883. */
  10884. @JRubyModule(name="Digest")
  10885. public class RubyDigest {
  10886. private static Provider provider = null;
  10887. public static void createDigest(Ruby runtime) {
  10888. try {
  10889. provider = (Provider) Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider").newInstance();
  10890. } catch(Exception e) {
  10891. // provider is not available
  10892. }
  10893. RubyModule mDigest = runtime.defineModule("Digest");
  10894. RubyClass cDigestBase = mDigest.defineClassUnder("Base",runtime.getObject(), Base.BASE_ALLOCATOR);
  10895. cDigestBase.defineAnnotatedMethods(Base.class);
  10896. }
  10897. private static MessageDigest createMessageDigest(Ruby runtime, String providerName) throws NoSuchAlgorithmException {
  10898. if(provider != null) {
  10899. try {
  10900. return MessageDigest.getInstance(providerName, provider);
  10901. } catch(NoSuchAlgorithmException e) {
  10902. // bouncy castle doesn't support algorithm
  10903. }
  10904. }
  10905. // fall back to system JCA providers
  10906. return MessageDigest.getInstance(providerName);
  10907. }
  10908. @JRubyClass(name="Digest::MD5", parent="Digest::Base")
  10909. public static class MD5 {}
  10910. @JRubyClass(name="Digest::RMD160", parent="Digest::Base")
  10911. public static class RMD160 {}
  10912. @JRubyClass(name="Digest::SHA1", parent="Digest::Base")
  10913. public static class SHA1 {}
  10914. @JRubyClass(name="Digest::SHA256", parent="Digest::Base")
  10915. public static class SHA256 {}
  10916. @JRubyClass(name="Digest::SHA384", parent="Digest::Base")
  10917. public static class SHA384 {}
  10918. @JRubyClass(name="Digest::SHA512", parent="Digest::Base")
  10919. public static class SHA512 {}
  10920. public static void createDigestMD5(Ruby runtime) {
  10921. runtime.getLoadService().require("digest.so");
  10922. RubyModule mDigest = runtime.fastGetModule("Digest");
  10923. RubyClass cDigestBase = mDigest.fastGetClass("Base");
  10924. RubyClass cDigest_MD5 = mDigest.defineClassUnder("MD5",cDigestBase,cDigestBase.getAllocator());
  10925. cDigest_MD5.defineFastMethod("block_length", new Callback() {
  10926. public Arity getArity() {
  10927. return Arity.NO_ARGUMENTS;
  10928. }
  10929. public IRubyObject execute(IRubyObject recv, IRubyObject[] args, Block block) {
  10930. return RubyFixnum.newFixnum(recv.getRuntime(), 64);
  10931. }
  10932. });
  10933. cDigest_MD5.setInternalModuleVariable("metadata",runtime.newString("MD5"));
  10934. }
  10935. public static void createDigestRMD160(Ruby runtime) {
  10936. runtime.getLoadService().require("digest.so");
  10937. if(provider == null) {
  10938. throw runtime.newLoadError("RMD160 not supported without BouncyCastle");
  10939. }
  10940. RubyModule mDigest = runtime.fastGetModule("Digest");
  10941. RubyClass cDigestBase = mDigest.fastGetClass("Base");
  10942. RubyClass cDigest_RMD160 = mDigest.defineClassUnder("RMD160",cDigestBase,cDigestBase.getAllocator());
  10943. cDigest_RMD160.setInternalModuleVariable("metadata",runtime.newString("RIPEMD160"));
  10944. }
  10945. public static void createDigestSHA1(Ruby runtime) {
  10946. runtime.getLoadService().require("digest.so");
  10947. RubyModule mDigest = runtime.fastGetModule("Digest");
  10948. RubyClass cDigestBase = mDigest.fastGetClass("Base");
  10949. RubyClass cDigest_SHA1 = mDigest.defineClassUnder("SHA1",cDigestBase,cDigestBase.getAllocator());
  10950. cDigest_SHA1.setInternalModuleVariable("metadata",runtime.newString("SHA1"));
  10951. }
  10952. public static void createDigestSHA2(Ruby runtime) {
  10953. runtime.getLoadService().require("digest.so");
  10954. try {
  10955. createMessageDigest(runtime, "SHA-256");
  10956. } catch(NoSuchAlgorithmException e) {
  10957. throw runtime.newLoadError("SHA2 not supported");
  10958. }
  10959. RubyModule mDigest = runtime.fastGetModule("Digest");
  10960. RubyClass cDigestBase = mDigest.fastGetClass("Base");
  10961. RubyClass cDigest_SHA2_256 = mDigest.defineClassUnder("SHA256",cDigestBase,cDigestBase.getAllocator());
  10962. cDigest_SHA2_256.setInternalModuleVariable("metadata",runtime.newString("SHA-256"));
  10963. RubyClass cDigest_SHA2_384 = mDigest.defineClassUnder("SHA384",cDigestBase,cDigestBase.getAllocator());
  10964. cDigest_SHA2_384.setInternalModuleVariable("metadata",runtime.newString("SHA-384"));
  10965. RubyClass cDigest_SHA2_512 = mDigest.defineClassUnder("SHA512",cDigestBase,cDigestBase.getAllocator());
  10966. cDigest_SHA2_512.setInternalModuleVariable("metadata",runtime.newString("SHA-512"));
  10967. }
  10968. @JRubyClass(name="Digest::Base")
  10969. public static class Base extends RubyObject {
  10970. protected static final ObjectAllocator BASE_ALLOCATOR = new ObjectAllocator() {
  10971. public IRubyObject allocate(Ruby runtime, RubyClass klass) {
  10972. return new Base(runtime, klass);
  10973. }
  10974. };
  10975. @JRubyMethod(name = "digest", required = 1, meta = true)
  10976. public static IRubyObject s_digest(IRubyObject recv, IRubyObject str) {
  10977. Ruby runtime = recv.getRuntime();
  10978. String name = ((RubyClass)recv).searchInternalModuleVariable("metadata").toString();
  10979. try {
  10980. MessageDigest md = createMessageDigest(runtime, name);
  10981. return RubyString.newString(runtime, md.digest(str.convertToString().getBytes()));
  10982. } catch(NoSuchAlgorithmException e) {
  10983. throw recv.getRuntime().newNotImplementedError("Unsupported digest algorithm (" + name + ")");
  10984. }
  10985. }
  10986. @JRubyMethod(name = "hexdigest", required = 1, meta = true)
  10987. public static IRubyObject s_hexdigest(IRubyObject recv, IRubyObject str) {
  10988. Ruby runtime = recv.getRuntime();
  10989. String name = ((RubyClass)recv).searchInternalModuleVariable("metadata").toString();
  10990. try {
  10991. MessageDigest md = createMessageDigest(runtime, name);
  10992. return RubyString.newString(runtime, ByteList.plain(toHex(md.digest(str.convertToString().getBytes()))));
  10993. } catch(NoSuchAlgorithmException e) {
  10994. throw recv.getRuntime().newNotImplementedError("Unsupported digest algorithm (" + name + ")");
  10995. }
  10996. }
  10997. private MessageDigest algo;
  10998. private StringBuffer data;
  10999. public Base(Ruby runtime, RubyClass type) {
  11000. super(runtime,type);
  11001. data = new StringBuffer();
  11002. if(type == runtime.fastGetModule("Digest").fastGetClass("Base")) {
  11003. throw runtime.newNotImplementedError("Digest::Base is an abstract class");
  11004. }
  11005. if(!type.hasInternalModuleVariable("metadata")) {
  11006. throw runtime.newNotImplementedError("the " + type + "() function is unimplemented on this machine");
  11007. }
  11008. try {
  11009. setAlgorithm(type.searchInternalModuleVariable("metadata"));
  11010. } catch(NoSuchAlgorithmException e) {
  11011. throw runtime.newNotImplementedError("the " + type + "() function is unimplemented on this machine");
  11012. }
  11013. }
  11014. @JRubyMethod(name = "initialize", optional = 1, frame = true)
  11015. public IRubyObject initialize(IRubyObject[] args, Block unusedBlock) {
  11016. if(args.length > 0 && !args[0].isNil()) {
  11017. update(args[0]);
  11018. }
  11019. return this;
  11020. }
  11021. @JRubyMethod(name = "initialize_copy", required = 1)
  11022. public IRubyObject initialize_copy(IRubyObject obj) {
  11023. if(this == obj) {
  11024. return this;
  11025. }
  11026. ((RubyObject)obj).checkFrozen();
  11027. data = new StringBuffer(((Base)obj).data.toString());
  11028. String name = ((Base)obj).algo.getAlgorithm();
  11029. try {
  11030. algo = createMessageDigest(getRuntime(), name);
  11031. } catch(NoSuchAlgorithmException e) {
  11032. throw getRuntime().newNotImplementedError("Unsupported digest algorithm (" + name + ")");
  11033. }
  11034. return this;
  11035. }
  11036. @JRubyMethod(name = {"update", "<<"}, required = 1)
  11037. public IRubyObject update(IRubyObject obj) {
  11038. data.append(obj);
  11039. return this;
  11040. }
  11041. @JRubyMethod(name = "digest", optional = 1)
  11042. public IRubyObject digest(IRubyObject[] args) {
  11043. if (args.length == 1) {
  11044. reset();
  11045. data.append(args[0]);
  11046. }
  11047. IRubyObject digest = getDigest();
  11048. if (args.length == 1) {
  11049. reset();
  11050. }
  11051. return digest;
  11052. }
  11053. private IRubyObject getDigest() {
  11054. algo.reset();
  11055. return RubyString.newString(getRuntime(), algo.digest(ByteList.plain(data)));
  11056. }
  11057. @JRubyMethod(name = "digest!")
  11058. public IRubyObject digest_bang() {
  11059. algo.reset();
  11060. byte[] digest = algo.digest(ByteList.plain(data));
  11061. reset();
  11062. return RubyString.newString(getRuntime(), digest);
  11063. }
  11064. @JRubyMethod(name = {"hexdigest"}, optional = 1)
  11065. public IRubyObject hexdigest(IRubyObject[] args) {
  11066. algo.reset();
  11067. if (args.length == 1) {
  11068. reset();
  11069. data.append(args[0]);
  11070. }
  11071. byte[] digest = ByteList.plain(toHex(algo.digest(ByteList.plain(data))));
  11072. if (args.length == 1) {
  11073. reset();
  11074. }
  11075. return RubyString.newString(getRuntime(), digest);
  11076. }
  11077. @JRubyMethod(name = {"to_s"})
  11078. public IRubyObject to_s() {
  11079. algo.reset();
  11080. return RubyString.newString(getRuntime(), ByteList.plain(toHex(algo.digest(ByteList.plain(data)))));
  11081. }
  11082. @JRubyMethod(name = {"hexdigest!"})
  11083. public IRubyObject hexdigest_bang() {
  11084. algo.reset();
  11085. byte[] digest = ByteList.plain(toHex(algo.digest(ByteList.plain(data))));
  11086. reset();
  11087. return RubyString.newString(getRuntime(), digest);
  11088. }
  11089. @JRubyMethod(name = "inspect")
  11090. public IRubyObject inspect() {
  11091. algo.reset();
  11092. return RubyString.newString(getRuntime(), ByteList.plain("#<" + getMetaClass().getRealClass().getName() + ": " + toHex(algo.digest(ByteList.plain(data))) + ">"));
  11093. }
  11094. @JRubyMethod(name = "==", required = 1)
  11095. public IRubyObject op_equal(IRubyObject oth) {
  11096. boolean ret = this == oth;
  11097. if(!ret) {
  11098. if (oth instanceof Base) {
  11099. Base b = (Base)oth;
  11100. ret = this.algo.getAlgorithm().equals(b.algo.getAlgorithm()) &&
  11101. this.getDigest().equals(b.getDigest());
  11102. } else {
  11103. IRubyObject str = oth.convertToString();
  11104. ret = this.to_s().equals(str);
  11105. }
  11106. }
  11107. return ret ? getRuntime().getTrue() : getRuntime().getFalse();
  11108. }
  11109. @JRubyMethod(name = {"length", "size", "digest_length"})
  11110. public IRubyObject length() {
  11111. return RubyFixnum.newFixnum(getRuntime(), algo.getDigestLength());
  11112. }
  11113. @JRubyMethod(name = {"block_length"})
  11114. public IRubyObject block_length() {
  11115. throw getRuntime().newRuntimeError(
  11116. this.getMetaClass() + " doesn't implement block_length()");
  11117. }
  11118. @JRubyMethod(name = {"reset"})
  11119. public IRubyObject reset() {
  11120. algo.reset();
  11121. data = new StringBuffer();
  11122. return getRuntime().getNil();
  11123. }
  11124. private void setAlgorithm(IRubyObject algo) throws NoSuchAlgorithmException {
  11125. this.algo = createMessageDigest(getRuntime(), algo.toString());
  11126. }
  11127. private static String toHex(byte[] val) {
  11128. StringBuilder out = new StringBuilder();
  11129. for(int i=0,j=val.length;i<j;i++) {
  11130. String ve = Integer.toString((((int)((char)val[i])) & 0xFF),16);
  11131. if(ve.length() == 1) {
  11132. ve = "0" + ve;
  11133. }
  11134. out.append(ve);
  11135. }
  11136. return out.toString();
  11137. }
  11138. }
  11139. }// RubyDigest
  11140. /***** BEGIN LICENSE BLOCK *****
  11141. * Version: CPL 1.0/GPL 2.0/LGPL 2.1
  11142. *
  11143. * The contents of this file are subject to the Common Public
  11144. * License Version 1.0 (the "License"); you may not use this file
  11145. * except in compliance with the License. You may obtain a copy of
  11146. * the License at http://www.eclipse.org/legal/cpl-v10.html
  11147. *
  11148. * Software distributed under the License is distributed on an "AS
  11149. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  11150. * implied. See the License for the specific language governing
  11151. * rights and limitations under the License.
  11152. *
  11153. * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
  11154. * Copyright (C) 2002-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
  11155. * Copyright (C) 2004 Thomas E Enebo <enebo@acm.org>
  11156. * Copyright (C) 2004-2005 Charles O Nutter <headius@headius.com>
  11157. * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
  11158. *
  11159. * Alternatively, the contents of this file may be used under the terms of
  11160. * either of the GNU General Public License Version 2 or later (the "GPL"),
  11161. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  11162. * in which case the provisions of the GPL or the LGPL are applicable instead
  11163. * of those above. If you wish to allow use of your version of this file only
  11164. * under the terms of either the GPL or the LGPL, and not to allow others to
  11165. * use your version of this file under the terms of the CPL, indicate your
  11166. * decision by deleting the provisions above and replace them with the notice
  11167. * and other provisions required by the GPL or the LGPL. If you do not delete
  11168. * the provisions above, a recipient may use your version of this file under
  11169. * the terms of any one of the CPL, the GPL or the LGPL.
  11170. ***** END LICENSE BLOCK *****/
  11171. package org.jruby;
  11172. import java.io.File;
  11173. import java.io.FileInputStream;
  11174. import java.io.IOException;
  11175. import java.util.ArrayList;
  11176. import java.util.List;
  11177. import org.jruby.anno.JRubyMethod;
  11178. import org.jruby.anno.JRubyClass;
  11179. import org.jruby.ext.posix.util.Platform;
  11180. import org.jruby.javasupport.JavaUtil;
  11181. import org.jruby.runtime.Block;
  11182. import org.jruby.runtime.ObjectAllocator;
  11183. import org.jruby.runtime.ThreadContext;
  11184. import org.jruby.runtime.builtin.IRubyObject;
  11185. import org.jruby.util.Dir;
  11186. import org.jruby.util.JRubyFile;
  11187. import org.jruby.util.ByteList;
  11188. /**
  11189. * .The Ruby built-in class Dir.
  11190. *
  11191. * @author jvoegele
  11192. */
  11193. @JRubyClass(name="Dir", include="Enumerable")
  11194. public class RubyDir extends RubyObject {
  11195. // What we passed to the constructor for method 'path'
  11196. private RubyString path;
  11197. protected JRubyFile dir;
  11198. private String[] snapshot; // snapshot of contents of directory
  11199. private int pos; // current position in directory
  11200. private boolean isOpen = true;
  11201. public RubyDir(Ruby runtime, RubyClass type) {
  11202. super(runtime, type);
  11203. }
  11204. private static final ObjectAllocator DIR_ALLOCATOR = new ObjectAllocator() {
  11205. public IRubyObject allocate(Ruby runtime, RubyClass klass) {
  11206. return new RubyDir(runtime, klass);
  11207. }
  11208. };
  11209. public static RubyClass createDirClass(Ruby runtime) {
  11210. RubyClass dirClass = runtime.defineClass("Dir", runtime.getObject(), DIR_ALLOCATOR);
  11211. runtime.setDir(dirClass);
  11212. dirClass.includeModule(runtime.getEnumerable());
  11213. dirClass.defineAnnotatedMethods(RubyDir.class);
  11214. return dirClass;
  11215. }
  11216. private final void checkDir() {
  11217. if (!isTaint() && getRuntime().getSafeLevel() >= 4) throw getRuntime().newSecurityError("Insecure: operation on untainted Dir");
  11218. testFrozen("");
  11219. if (!isOpen) throw getRuntime().newIOError("closed directory");
  11220. }
  11221. /**
  11222. * Creates a new <code>Dir</code>. This method takes a snapshot of the
  11223. * contents of the directory at creation time, so changes to the contents
  11224. * of the directory will not be reflected during the lifetime of the
  11225. * <code>Dir</code> object returned, so a new <code>Dir</code> instance
  11226. * must be created to reflect changes to the underlying file system.
  11227. */
  11228. @JRubyMethod(name = "initialize", required = 1, frame = true)
  11229. public IRubyObject initialize(IRubyObject _newPath, Block unusedBlock) {
  11230. RubyString newPath = _newPath.convertToString();
  11231. getRuntime().checkSafeString(newPath);
  11232. String adjustedPath = RubyFile.adjustRootPathOnWindows(getRuntime(), newPath.toString(), null);
  11233. checkDirIsTwoSlashesOnWindows(getRuntime(), adjustedPath);
  11234. dir = JRubyFile.create(getRuntime().getCurrentDirectory(), adjustedPath);
  11235. if (!dir.isDirectory()) {
  11236. dir = null;
  11237. throw getRuntime().newErrnoENOENTError(newPath.toString() + " is not a directory");
  11238. }
  11239. path = newPath;
  11240. List<String> snapshotList = new ArrayList<String>();
  11241. snapshotList.add(".");
  11242. snapshotList.add("..");
  11243. snapshotList.addAll(getContents(dir));
  11244. snapshot = (String[]) snapshotList.toArray(new String[snapshotList.size()]);
  11245. pos = 0;
  11246. return this;
  11247. }
  11248. // ----- Ruby Class Methods ----------------------------------------------------
  11249. private static List<ByteList> dirGlobs(String cwd, IRubyObject[] args, int flags) {
  11250. List<ByteList> dirs = new ArrayList<ByteList>();
  11251. for (int i = 0; i < args.length; i++) {
  11252. ByteList globPattern = args[i].convertToString().getByteList();
  11253. dirs.addAll(Dir.push_glob(cwd, globPattern, flags));
  11254. }
  11255. return dirs;
  11256. }
  11257. private static IRubyObject asRubyStringList(Ruby runtime, List<ByteList> dirs) {
  11258. List<RubyString> allFiles = new ArrayList<RubyString>();
  11259. for (ByteList dir: dirs) {
  11260. allFiles.add(RubyString.newString(runtime, dir));
  11261. }
  11262. IRubyObject[] tempFileList = new IRubyObject[allFiles.size()];
  11263. allFiles.toArray(tempFileList);
  11264. return runtime.newArrayNoCopy(tempFileList);
  11265. }
  11266. private static String getCWD(Ruby runtime) {
  11267. try {
  11268. return new org.jruby.util.NormalizedFile(runtime.getCurrentDirectory()).getCanonicalPath();
  11269. } catch(Exception e) {
  11270. return runtime.getCurrentDirectory();
  11271. }
  11272. }
  11273. @JRubyMethod(name = "[]", required = 1, rest=true, meta = true)
  11274. public static IRubyObject aref(IRubyObject recv, IRubyObject[] args) {
  11275. List<ByteList> dirs;
  11276. if (args.length == 1) {
  11277. ByteList globPattern = args[0].convertToString().getByteList();
  11278. dirs = Dir.push_glob(getCWD(recv.getRuntime()), globPattern, 0);
  11279. } else {
  11280. dirs = dirGlobs(getCWD(recv.getRuntime()), args, 0);
  11281. }
  11282. return asRubyStringList(recv.getRuntime(), dirs);
  11283. }
  11284. /**
  11285. * Returns an array of filenames matching the specified wildcard pattern
  11286. * <code>pat</code>. If a block is given, the array is iterated internally
  11287. * with each filename is passed to the block in turn. In this case, Nil is
  11288. * returned.
  11289. */
  11290. @JRubyMethod(name = "glob", required = 1, optional = 1, frame = true, meta = true)
  11291. public static IRubyObject glob(ThreadContext context, IRubyObject recv, IRubyObject[] args, Block block) {
  11292. Ruby runtime = recv.getRuntime();
  11293. int flags = args.length == 2 ? RubyNumeric.num2int(args[1]) : 0;
  11294. List<ByteList> dirs;
  11295. IRubyObject tmp = args[0].checkArrayType();
  11296. if (tmp.isNil()) {
  11297. ByteList globPattern = args[0].convertToString().getByteList();
  11298. dirs = Dir.push_glob(recv.getRuntime().getCurrentDirectory(), globPattern, flags);
  11299. } else {
  11300. dirs = dirGlobs(getCWD(runtime), ((RubyArray) tmp).toJavaArray(), flags);
  11301. }
  11302. if (block.isGiven()) {
  11303. for (int i = 0; i < dirs.size(); i++) {
  11304. block.yield(context, RubyString.newString(runtime, dirs.get(i)));
  11305. }
  11306. return recv.getRuntime().getNil();
  11307. }
  11308. return asRubyStringList(recv.getRuntime(), dirs);
  11309. }
  11310. /**
  11311. * @return all entries for this Dir
  11312. */
  11313. @JRubyMethod(name = "entries")
  11314. public RubyArray entries() {
  11315. return getRuntime().newArrayNoCopy(JavaUtil.convertJavaArrayToRuby(getRuntime(), snapshot));
  11316. }
  11317. /**
  11318. * Returns an array containing all of the filenames in the given directory.
  11319. */
  11320. @JRubyMethod(name = "entries", required = 1, meta = true)
  11321. public static RubyArray entries(IRubyObject recv, IRubyObject path) {
  11322. Ruby runtime = recv.getRuntime();
  11323. String adjustedPath = RubyFile.adjustRootPathOnWindows(
  11324. runtime, path.convertToString().toString(), null);
  11325. checkDirIsTwoSlashesOnWindows(runtime, adjustedPath);
  11326. final JRubyFile directory = JRubyFile.create(
  11327. recv.getRuntime().getCurrentDirectory(), adjustedPath);
  11328. if (!directory.isDirectory()) {
  11329. throw recv.getRuntime().newErrnoENOENTError("No such directory");
  11330. }
  11331. List<String> fileList = getContents(directory);
  11332. fileList.add(0, ".");
  11333. fileList.add(1, "..");
  11334. Object[] files = fileList.toArray();
  11335. return recv.getRuntime().newArrayNoCopy(JavaUtil.convertJavaArrayToRuby(recv.getRuntime(), files));
  11336. }
  11337. // MRI behavior: just plain '//' or '\\\\' are considered illegal on Windows.
  11338. private static void checkDirIsTwoSlashesOnWindows(Ruby runtime, String path) {
  11339. if (Platform.IS_WINDOWS && ("//".equals(path) || "\\\\".equals(path))) {
  11340. throw runtime.newErrnoEINVALError("Invalid argument - " + path);
  11341. }
  11342. }
  11343. /** Changes the current directory to <code>path</code> */
  11344. @JRubyMethod(name = "chdir", optional = 1, frame = true, meta = true)
  11345. public static IRubyObject chdir(ThreadContext context, IRubyObject recv, IRubyObject[] args, Block block) {
  11346. RubyString path = args.length == 1 ?
  11347. (RubyString) args[0].convertToString() : getHomeDirectoryPath(context);
  11348. String adjustedPath = RubyFile.adjustRootPathOnWindows(
  11349. recv.getRuntime(), path.toString(), null);
  11350. checkDirIsTwoSlashesOnWindows(recv.getRuntime(), adjustedPath);
  11351. JRubyFile dir = getDir(recv.getRuntime(), adjustedPath, true);
  11352. String realPath = null;
  11353. String oldCwd = recv.getRuntime().getCurrentDirectory();
  11354. // We get canonical path to try and flatten the path out.
  11355. // a dir '/subdir/..' should return as '/'
  11356. // cnutter: Do we want to flatten path out?
  11357. try {
  11358. realPath = dir.getCanonicalPath();
  11359. } catch (IOException e) {
  11360. realPath = dir.getAbsolutePath();
  11361. }
  11362. IRubyObject result = null;
  11363. if (block.isGiven()) {
  11364. // FIXME: Don't allow multiple threads to do this at once
  11365. recv.getRuntime().setCurrentDirectory(realPath);
  11366. try {
  11367. result = block.yield(context, path);
  11368. } finally {
  11369. dir = getDir(recv.getRuntime(), oldCwd, true);
  11370. recv.getRuntime().setCurrentDirectory(oldCwd);
  11371. }
  11372. } else {
  11373. recv.getRuntime().setCurrentDirectory(realPath);
  11374. result = recv.getRuntime().newFixnum(0);
  11375. }
  11376. return result;
  11377. }
  11378. /**
  11379. * Changes the root directory (only allowed by super user). Not available
  11380. * on all platforms.
  11381. */
  11382. @JRubyMethod(name = "chroot", required = 1, meta = true)
  11383. public static IRubyObject chroot(IRubyObject recv, IRubyObject path) {
  11384. throw recv.getRuntime().newNotImplementedError("chroot not implemented: chroot is non-portable and is not supported.");
  11385. }
  11386. /**
  11387. * Deletes the directory specified by <code>path</code>. The directory must
  11388. * be empty.
  11389. */
  11390. @JRubyMethod(name = {"rmdir", "unlink", "delete"}, required = 1, meta = true)
  11391. public static IRubyObject rmdir(IRubyObject recv, IRubyObject path) {
  11392. JRubyFile directory = getDir(recv.getRuntime(), path.convertToString().toString(), true);
  11393. if (!directory.delete()) {
  11394. throw recv.getRuntime().newSystemCallError("No such directory");
  11395. }
  11396. return recv.getRuntime().newFixnum(0);
  11397. }
  11398. /**
  11399. * Executes the block once for each file in the directory specified by
  11400. * <code>path</code>.
  11401. */
  11402. @JRubyMethod(name = "foreach", required = 1, frame = true, meta = true)
  11403. public static IRubyObject foreach(ThreadContext context, IRubyObject recv, IRubyObject _path, Block block) {
  11404. RubyString path = _path.convertToString();
  11405. recv.getRuntime().checkSafeString(path);
  11406. RubyClass dirClass = recv.getRuntime().getDir();
  11407. RubyDir dir = (RubyDir) dirClass.newInstance(context, new IRubyObject[] { path }, block);
  11408. dir.each(context, block);
  11409. return recv.getRuntime().getNil();
  11410. }
  11411. /** Returns the current directory. */
  11412. @JRubyMethod(name = {"getwd", "pwd"}, meta = true)
  11413. public static RubyString getwd(IRubyObject recv) {
  11414. Ruby ruby = recv.getRuntime();
  11415. return RubyString.newUnicodeString(ruby, ruby.getCurrentDirectory());
  11416. }
  11417. /**
  11418. * Creates the directory specified by <code>path</code>. Note that the
  11419. * <code>mode</code> parameter is provided only to support existing Ruby
  11420. * code, and is ignored.
  11421. */
  11422. @JRubyMethod(name = "mkdir", required = 1, optional = 1, meta = true)
  11423. public static IRubyObject mkdir(IRubyObject recv, IRubyObject[] args) {
  11424. Ruby runtime = recv.getRuntime();
  11425. runtime.checkSafeString(args[0]);
  11426. String path = args[0].toString();
  11427. File newDir = getDir(runtime, path, false);
  11428. if (File.separatorChar == '\\') {
  11429. newDir = new File(newDir.getPath());
  11430. }
  11431. int mode = args.length == 2 ? ((int) args[1].convertToInteger().getLongValue()) : 0777;
  11432. if (runtime.getPosix().mkdir(newDir.getAbsolutePath(), mode) < 0) {
  11433. // FIXME: This is a system error based on errno
  11434. throw recv.getRuntime().newSystemCallError("mkdir failed");
  11435. }
  11436. return RubyFixnum.zero(recv.getRuntime());
  11437. }
  11438. /**
  11439. * Returns a new directory object for <code>path</code>. If a block is
  11440. * provided, a new directory object is passed to the block, which closes the
  11441. * directory object before terminating.
  11442. */
  11443. @JRubyMethod(name = "open", required = 1, frame = true, meta = true)
  11444. public static IRubyObject open(ThreadContext context, IRubyObject recv, IRubyObject path, Block block) {
  11445. RubyDir directory =
  11446. (RubyDir) recv.getRuntime().getDir().newInstance(context,
  11447. new IRubyObject[] { path }, Block.NULL_BLOCK);
  11448. if (!block.isGiven()) return directory;
  11449. try {
  11450. return block.yield(context, directory);
  11451. } finally {
  11452. directory.close();
  11453. }
  11454. }
  11455. // ----- Ruby Instance Methods -------------------------------------------------
  11456. /**
  11457. * Closes the directory stream.
  11458. */
  11459. @JRubyMethod(name = "close")
  11460. public IRubyObject close() {
  11461. // Make sure any read()s after close fail.
  11462. checkDir();
  11463. isOpen = false;
  11464. return getRuntime().getNil();
  11465. }
  11466. /**
  11467. * Executes the block once for each entry in the directory.
  11468. */
  11469. @JRubyMethod(name = "each", frame = true)
  11470. public IRubyObject each(ThreadContext context, Block block) {
  11471. checkDir();
  11472. String[] contents = snapshot;
  11473. for (int i=0; i<contents.length; i++) {
  11474. block.yield(context, getRuntime().newString(contents[i]));
  11475. }
  11476. return this;
  11477. }
  11478. /**
  11479. * Returns the current position in the directory.
  11480. */
  11481. @JRubyMethod(name = {"tell", "pos"})
  11482. public RubyInteger tell() {
  11483. checkDir();
  11484. return getRuntime().newFixnum(pos);
  11485. }
  11486. /**
  11487. * Moves to a position <code>d</code>. <code>pos</code> must be a value
  11488. * returned by <code>tell</code> or 0.
  11489. */
  11490. @JRubyMethod(name = "seek", required = 1)
  11491. public IRubyObject seek(IRubyObject newPos) {
  11492. checkDir();
  11493. set_pos(newPos);
  11494. return this;
  11495. }
  11496. @JRubyMethod(name = "pos=", required = 1)
  11497. public IRubyObject set_pos(IRubyObject newPos) {
  11498. this.pos = RubyNumeric.fix2int(newPos);
  11499. return newPos;
  11500. }
  11501. @JRubyMethod(name = "path")
  11502. public IRubyObject path(ThreadContext context) {
  11503. checkDir();
  11504. return path.strDup(context.getRuntime());
  11505. }
  11506. /** Returns the next entry from this directory. */
  11507. @JRubyMethod(name = "read")
  11508. public IRubyObject read() {
  11509. checkDir();
  11510. if (pos >= snapshot.length) {
  11511. return getRuntime().getNil();
  11512. }
  11513. RubyString result = getRuntime().newString(snapshot[pos]);
  11514. pos++;
  11515. return result;
  11516. }
  11517. /** Moves position in this directory to the first entry. */
  11518. @JRubyMethod(name = "rewind")
  11519. public IRubyObject rewind() {
  11520. if (!isTaint() && getRuntime().getSafeLevel() >= 4) throw getRuntime().newSecurityError("Insecure: can't close");
  11521. checkDir();
  11522. pos = 0;
  11523. return this;
  11524. }
  11525. // ----- Helper Methods --------------------------------------------------------
  11526. /** Returns a Java <code>File</code> object for the specified path. If
  11527. * <code>path</code> is not a directory, throws <code>IOError</code>.
  11528. *
  11529. * @param path path for which to return the <code>File</code> object.
  11530. * @param mustExist is true the directory must exist. If false it must not.
  11531. * @throws IOError if <code>path</code> is not a directory.
  11532. */
  11533. protected static JRubyFile getDir(final Ruby runtime, final String path, final boolean mustExist) {
  11534. JRubyFile result = JRubyFile.create(runtime.getCurrentDirectory(),path);
  11535. if (mustExist && !result.exists()) {
  11536. throw runtime.newErrnoENOENTError("No such file or directory - " + path);
  11537. }
  11538. boolean isDirectory = result.isDirectory();
  11539. if (mustExist && !isDirectory) {
  11540. throw runtime.newErrnoENOTDIRError(path + " is not a directory");
  11541. } else if (!mustExist && isDirectory) {
  11542. throw runtime.newErrnoEEXISTError("File exists - " + path);
  11543. }
  11544. return result;
  11545. }
  11546. /**
  11547. * Returns the contents of the specified <code>directory</code> as an
  11548. * <code>ArrayList</code> containing the names of the files as Java Strings.
  11549. */
  11550. protected static List<String> getContents(File directory) {
  11551. String[] contents = directory.list();
  11552. List<String> result = new ArrayList<String>();
  11553. // If an IO exception occurs (something odd, but possible)
  11554. // A directory may return null.
  11555. if (contents != null) {
  11556. for (int i=0; i<contents.length; i++) {
  11557. result.add(contents[i]);
  11558. }
  11559. }
  11560. return result;
  11561. }
  11562. /**
  11563. * Returns the contents of the specified <code>directory</code> as an
  11564. * <code>ArrayList</code> containing the names of the files as Ruby Strings.
  11565. */
  11566. protected static List<RubyString> getContents(File directory, Ruby runtime) {
  11567. List<RubyString> result = new ArrayList<RubyString>();
  11568. String[] contents = directory.list();
  11569. for (int i = 0; i < contents.length; i++) {
  11570. result.add(runtime.newString(contents[i]));
  11571. }
  11572. return result;
  11573. }
  11574. /**
  11575. * Returns the home directory of the specified <code>user</code> on the
  11576. * system. If the home directory of the specified user cannot be found,
  11577. * an <code>ArgumentError it thrown</code>.
  11578. */
  11579. public static IRubyObject getHomeDirectoryPath(ThreadContext context, String user) {
  11580. /*
  11581. * TODO: This version is better than the hackish previous one. Windows
  11582. * behavior needs to be defined though. I suppose this version
  11583. * could be improved more too.
  11584. * TODO: /etc/passwd is also inadequate for MacOSX since it does not
  11585. * use /etc/passwd for regular user accounts
  11586. */
  11587. String passwd = null;
  11588. try {
  11589. FileInputStream stream = new FileInputStream("/etc/passwd");
  11590. int totalBytes = stream.available();
  11591. byte[] bytes = new byte[totalBytes];
  11592. stream.read(bytes);
  11593. stream.close();
  11594. passwd = new String(bytes);
  11595. } catch (IOException e) {
  11596. return context.getRuntime().getNil();
  11597. }
  11598. String[] rows = passwd.split("\n");
  11599. int rowCount = rows.length;
  11600. for (int i = 0; i < rowCount; i++) {
  11601. String[] fields = rows[i].split(":");
  11602. if (fields[0].equals(user)) {
  11603. return context.getRuntime().newString(fields[5]);
  11604. }
  11605. }
  11606. throw context.getRuntime().newArgumentError("user " + user + " doesn't exist");
  11607. }
  11608. public static RubyString getHomeDirectoryPath(ThreadContext context) {
  11609. Ruby runtime = context.getRuntime();
  11610. RubyHash systemHash = (RubyHash) runtime.getObject().fastGetConstant("ENV_JAVA");
  11611. RubyHash envHash = (RubyHash) runtime.getObject().fastGetConstant("ENV");
  11612. IRubyObject home = envHash.op_aref(context, runtime.newString("HOME"));
  11613. if (home == null || home.isNil()) {
  11614. home = systemHash.op_aref(context, runtime.newString("user.home"));
  11615. }
  11616. if (home == null || home.isNil()) {
  11617. home = envHash.op_aref(context, runtime.newString("LOGDIR"));
  11618. }
  11619. if (home == null || home.isNil()) {
  11620. throw runtime.newArgumentError("user.home/LOGDIR not set");
  11621. }
  11622. return (RubyString) home;
  11623. }
  11624. }
  11625. /***** BEGIN LICENSE BLOCK *****
  11626. * Version: CPL 1.0/GPL 2.0/LGPL 2.1
  11627. *
  11628. * The contents of this file are subject to the Common Public
  11629. * License Version 1.0 (the "License"); you may not use this file
  11630. * except in compliance with the License. You may obtain a copy of
  11631. * the License at http://www.eclipse.org/legal/cpl-v10.html
  11632. *
  11633. * Software distributed under the License is distributed on an "AS
  11634. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  11635. * implied. See the License for the specific language governing
  11636. * rights and limitations under the License.
  11637. *
  11638. * Copyright (C) 2006 Ola Bini <ola@ologix.com>
  11639. *
  11640. * Alternatively, the contents of this file may be used under the terms of
  11641. * either of the GNU General Public License Version 2 or later (the "GPL"),
  11642. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  11643. * in which case the provisions of the GPL or the LGPL are applicable instead
  11644. * of those above. If you wish to allow use of your version of this file only
  11645. * under the terms of either the GPL or the LGPL, and not to allow others to
  11646. * use your version of this file under the terms of the CPL, indicate your
  11647. * decision by deleting the provisions above and replace them with the notice
  11648. * and other provisions required by the GPL or the LGPL. If you do not delete
  11649. * the provisions above, a recipient may use your version of this file under
  11650. * the terms of any one of the CPL, the GPL or the LGPL.
  11651. ***** END LICENSE BLOCK *****/
  11652. package org.jruby;
  11653. import java.util.Comparator;
  11654. import java.util.Arrays;
  11655. import java.util.concurrent.atomic.AtomicInteger;
  11656. import org.jruby.anno.JRubyMethod;
  11657. import org.jruby.anno.JRubyModule;
  11658. import org.jruby.exceptions.JumpException;
  11659. import org.jruby.javasupport.util.RuntimeHelpers;
  11660. import org.jruby.runtime.Arity;
  11661. import org.jruby.runtime.Block;
  11662. import org.jruby.runtime.CallBlock;
  11663. import org.jruby.runtime.BlockCallback;
  11664. import org.jruby.runtime.MethodIndex;
  11665. import org.jruby.runtime.ThreadContext;
  11666. import org.jruby.runtime.builtin.IRubyObject;
  11667. import org.jruby.util.TypeConverter;
  11668. /**
  11669. * The implementation of Ruby's Enumerable module.
  11670. */
  11671. @JRubyModule(name="Enumerable")
  11672. public class RubyEnumerable {
  11673. public static RubyModule createEnumerableModule(Ruby runtime) {
  11674. RubyModule enumModule = runtime.defineModule("Enumerable");
  11675. runtime.setEnumerable(enumModule);
  11676. enumModule.defineAnnotatedMethods(RubyEnumerable.class);
  11677. return enumModule;
  11678. }
  11679. public static IRubyObject callEach(Ruby runtime, ThreadContext context, IRubyObject self,
  11680. BlockCallback callback) {
  11681. return RuntimeHelpers.invoke(context, self, "each", CallBlock.newCallClosure(self, runtime.getEnumerable(),
  11682. Arity.noArguments(), callback, context));
  11683. }
  11684. private static class ExitIteration extends RuntimeException {
  11685. public Throwable fillInStackTrace() {
  11686. return this;
  11687. }
  11688. }
  11689. @JRubyMethod(name = "first")
  11690. public static IRubyObject first_0(ThreadContext context, IRubyObject self) {
  11691. Ruby runtime = self.getRuntime();
  11692. final ThreadContext localContext = context;
  11693. final IRubyObject[] holder = new IRubyObject[]{runtime.getNil()};
  11694. try {
  11695. callEach(runtime, context, self, new BlockCallback() {
  11696. public IRubyObject call(ThreadContext ctx, IRubyObject[] largs, Block blk) {
  11697. if (localContext != ctx) {
  11698. throw ctx.getRuntime().newThreadError("Enumerable#first cannot be parallelized");
  11699. }
  11700. holder[0] = largs[0];
  11701. throw new ExitIteration();
  11702. }
  11703. });
  11704. } catch(ExitIteration ei) {}
  11705. return holder[0];
  11706. }
  11707. @JRubyMethod(name = "first")
  11708. public static IRubyObject first_1(ThreadContext context, IRubyObject self, final IRubyObject num) {
  11709. final Ruby runtime = self.getRuntime();
  11710. final RubyArray result = runtime.newArray();
  11711. final ThreadContext localContext = context;
  11712. if(RubyNumeric.fix2int(num) < 0) {
  11713. throw runtime.newArgumentError("negative index");
  11714. }
  11715. try {
  11716. callEach(runtime, context, self, new BlockCallback() {
  11717. private int iter = RubyNumeric.fix2int(num);
  11718. public IRubyObject call(ThreadContext ctx, IRubyObject[] largs, Block blk) {
  11719. if (localContext != ctx) {
  11720. throw runtime.newThreadError("Enumerable#first cannot be parallelized");
  11721. }
  11722. if(iter-- == 0) {
  11723. throw new ExitIteration();
  11724. }
  11725. result.append(largs[0]);
  11726. return runtime.getNil();
  11727. }
  11728. });
  11729. } catch(ExitIteration ei) {}
  11730. return result;
  11731. }
  11732. @JRubyMethod(name = {"to_a", "entries"})
  11733. public static IRubyObject to_a(ThreadContext context, IRubyObject self) {
  11734. Ruby runtime = self.getRuntime();
  11735. RubyArray result = runtime.newArray();
  11736. callEach(runtime, context, self, new AppendBlockCallback(runtime, result));
  11737. return result;
  11738. }
  11739. @JRubyMethod(name = "sort", frame = true)
  11740. public static IRubyObject sort(ThreadContext context, IRubyObject self, final Block block) {
  11741. Ruby runtime = self.getRuntime();
  11742. RubyArray result = runtime.newArray();
  11743. callEach(runtime, context, self, new AppendBlockCallback(runtime, result));
  11744. result.sort_bang(block);
  11745. return result;
  11746. }
  11747. @JRubyMethod(name = "sort_by", frame = true)
  11748. public static IRubyObject sort_by(ThreadContext context, IRubyObject self, final Block block) {
  11749. final Ruby runtime = self.getRuntime();
  11750. final ThreadContext localContext = context; // MUST NOT be used across threads
  11751. if (self instanceof RubyArray) {
  11752. RubyArray selfArray = (RubyArray) self;
  11753. final IRubyObject[][] valuesAndCriteria = new IRubyObject[selfArray.size()][2];
  11754. callEach(runtime, context, self, new BlockCallback() {
  11755. AtomicInteger i = new AtomicInteger(0);
  11756. public IRubyObject call(ThreadContext ctx, IRubyObject[] largs, Block blk) {
  11757. IRubyObject[] myVandC = valuesAndCriteria[i.getAndIncrement()];
  11758. myVandC[0] = largs[0];
  11759. myVandC[1] = block.yield(ctx, largs[0]);
  11760. return runtime.getNil();
  11761. }
  11762. });
  11763. Arrays.sort(valuesAndCriteria, new Comparator<IRubyObject[]>() {
  11764. public int compare(IRubyObject[] o1, IRubyObject[] o2) {
  11765. return RubyFixnum.fix2int(o1[1].callMethod(localContext, MethodIndex.OP_SPACESHIP, "<=>", o2[1]));
  11766. }
  11767. });
  11768. IRubyObject dstArray[] = new IRubyObject[selfArray.size()];
  11769. for (int i = 0; i < dstArray.length; i++) {
  11770. dstArray[i] = valuesAndCriteria[i][0];
  11771. }
  11772. return runtime.newArrayNoCopy(dstArray);
  11773. } else {
  11774. final RubyArray result = runtime.newArray();
  11775. callEach(runtime, context, self, new AppendBlockCallback(runtime, result));
  11776. final IRubyObject[][] valuesAndCriteria = new IRubyObject[result.size()][2];
  11777. for (int i = 0; i < valuesAndCriteria.length; i++) {
  11778. IRubyObject val = result.eltInternal(i);
  11779. valuesAndCriteria[i][0] = val;
  11780. valuesAndCriteria[i][1] = block.yield(context, val);
  11781. }
  11782. Arrays.sort(valuesAndCriteria, new Comparator<IRubyObject[]>() {
  11783. public int compare(IRubyObject[] o1, IRubyObject[] o2) {
  11784. return RubyFixnum.fix2int(o1[1].callMethod(localContext, MethodIndex.OP_SPACESHIP, "<=>", o2[1]));
  11785. }
  11786. });
  11787. for (int i = 0; i < valuesAndCriteria.length; i++) {
  11788. result.eltInternalSet(i, valuesAndCriteria[i][0]);
  11789. }
  11790. return result;
  11791. }
  11792. }
  11793. @JRubyMethod(name = "grep", required = 1, frame = true)
  11794. public static IRubyObject grep(ThreadContext context, IRubyObject self, final IRubyObject pattern, final Block block) {
  11795. final Ruby runtime = self.getRuntime();
  11796. final RubyArray result = runtime.newArray();
  11797. if (block.isGiven()) {
  11798. callEach(runtime, context, self, new BlockCallback() {
  11799. public IRubyObject call(ThreadContext ctx, IRubyObject[] largs, Block blk) {
  11800. ctx.setRubyFrameDelta(ctx.getRubyFrameDelta()+2);
  11801. if (pattern.callMethod(ctx, MethodIndex.OP_EQQ, "===", largs[0]).isTrue()) {
  11802. IRubyObject value = block.yield(ctx, largs[0]);
  11803. synchronized (result) {
  11804. result.append(value);
  11805. }
  11806. }
  11807. ctx.setRubyFrameDelta(ctx.getRubyFrameDelta()-2);
  11808. return runtime.getNil();
  11809. }
  11810. });
  11811. } else {
  11812. callEach(runtime, context, self, new BlockCallback() {
  11813. public IRubyObject call(ThreadContext ctx, IRubyObject[] largs, Block blk) {
  11814. if (pattern.callMethod(ctx, MethodIndex.OP_EQQ, "===", largs[0]).isTrue()) {
  11815. synchronized (result) {
  11816. result.append(largs[0]);
  11817. }
  11818. }
  11819. return runtime.getNil();
  11820. }
  11821. });
  11822. }
  11823. return result;
  11824. }
  11825. @JRubyMethod(name = {"detect", "find"}, optional = 1, frame = true)
  11826. public static IRubyObject detect(ThreadContext context, IRubyObject self, IRubyObject[] args, final Block block) {
  11827. final Ruby runtime = self.getRuntime();
  11828. final IRubyObject result[] = new IRubyObject[] { null };
  11829. final ThreadContext localContext = context;
  11830. IRubyObject ifnone = null;
  11831. if (args.length == 1) ifnone = args[0];
  11832. try {
  11833. callEach(runtime, context, self, new BlockCallback() {
  11834. public IRubyObject call(ThreadContext ctx, IRubyObject[] largs, Block blk) {
  11835. if (localContext != ctx) {
  11836. throw runtime.newThreadError("Enumerable#detect/find cannot be parallelized");
  11837. }
  11838. if (block.yield(ctx, largs[0]).isTrue()) {
  11839. result[0] = largs[0];
  11840. throw JumpException.SPECIAL_JUMP;
  11841. }
  11842. return runtime.getNil();
  11843. }
  11844. });
  11845. } catch (JumpException.SpecialJump sj) {
  11846. return result[0];
  11847. }
  11848. return ifnone != null ? ifnone.callMethod(context, "call") : runtime.getNil();
  11849. }
  11850. @JRubyMethod(name = {"select", "find_all"}, frame = true)
  11851. public static IRubyObject select(ThreadContext context, IRubyObject self, final Block block) {
  11852. final Ruby runtime = self.getRuntime();
  11853. final RubyArray result = runtime.newArray();
  11854. callEach(runtime, context, self, new BlockCallback() {
  11855. public IRubyObject call(ThreadContext ctx, IRubyObject[] largs, Block blk) {
  11856. if (block.yield(ctx, largs[0]).isTrue()) {
  11857. synchronized (result) {
  11858. result.append(largs[0]);
  11859. }
  11860. }
  11861. return runtime.getNil();
  11862. }
  11863. });
  11864. return result;
  11865. }
  11866. @JRubyMethod(name = "reject", frame = true)
  11867. public static IRubyObject reject(ThreadContext context, IRubyObject self, final Block block) {
  11868. final Ruby runtime = self.getRuntime();
  11869. final RubyArray result = runtime.newArray();
  11870. callEach(runtime, context, self, new BlockCallback() {
  11871. public IRubyObject call(ThreadContext ctx, IRubyObject[] largs, Block blk) {
  11872. if (!block.yield(ctx, largs[0]).isTrue()) {
  11873. synchronized (result) {
  11874. result.append(largs[0]);
  11875. }
  11876. }
  11877. return runtime.getNil();
  11878. }
  11879. });
  11880. return result;
  11881. }
  11882. @JRubyMethod(name = {"collect", "map"}, frame = true)
  11883. public static IRubyObject collect(ThreadContext context, IRubyObject self, final Block block) {
  11884. final Ruby runtime = self.getRuntime();
  11885. final RubyArray result = runtime.newArray();
  11886. if (block.isGiven()) {
  11887. callEach(runtime, context, self, new BlockCallback() {
  11888. public IRubyObject call(ThreadContext ctx, IRubyObject[] largs, Block blk) {
  11889. IRubyObject value = block.yield(ctx, largs[0]);
  11890. synchronized (result) {
  11891. result.append(value);
  11892. }
  11893. return runtime.getNil();
  11894. }
  11895. });
  11896. } else {
  11897. callEach(runtime, context, self, new AppendBlockCallback(runtime, result));
  11898. }
  11899. return result;
  11900. }
  11901. @JRubyMethod(name = "inject", optional = 1, frame = true)
  11902. public static IRubyObject inject(ThreadContext context, IRubyObject self, IRubyObject[] args, final Block block) {
  11903. final Ruby runtime = self.getRuntime();
  11904. final IRubyObject result[] = new IRubyObject[] { null };
  11905. final ThreadContext localContext = context;
  11906. if (args.length == 1) result[0] = args[0];
  11907. callEach(runtime, context, self, new BlockCallback() {
  11908. public IRubyObject call(ThreadContext ctx, IRubyObject[] largs, Block blk) {
  11909. if (localContext != ctx) {
  11910. throw runtime.newThreadError("Enumerable#inject cannot be parallelized");
  11911. }
  11912. result[0] = result[0] == null ?
  11913. largs[0] : block.yield(ctx, runtime.newArray(result[0], largs[0]), null, null, true);
  11914. return runtime.getNil();
  11915. }
  11916. });
  11917. return result[0] == null ? runtime.getNil() : result[0];
  11918. }
  11919. @JRubyMethod(name = "partition", frame = true)
  11920. public static IRubyObject partition(ThreadContext context, IRubyObject self, final Block block) {
  11921. final Ruby runtime = self.getRuntime();
  11922. final RubyArray arr_true = runtime.newArray();
  11923. final RubyArray arr_false = runtime.newArray();
  11924. callEach(runtime, context, self, new BlockCallback() {
  11925. public IRubyObject call(ThreadContext ctx, IRubyObject[] largs, Block blk) {
  11926. if (block.yield(ctx, largs[0]).isTrue()) {
  11927. synchronized (arr_true) {
  11928. arr_true.append(largs[0]);
  11929. }
  11930. } else {
  11931. synchronized (arr_false) {
  11932. arr_false.append(largs[0]);
  11933. }
  11934. }
  11935. return runtime.getNil();
  11936. }
  11937. });
  11938. return runtime.newArray(arr_true, arr_false);
  11939. }
  11940. private static class EachWithIndex implements BlockCallback {
  11941. private int index = 0;
  11942. private final Block block;
  11943. private final Ruby runtime;
  11944. public EachWithIndex(ThreadContext ctx, Block block) {
  11945. this.block = block;
  11946. this.runtime = ctx.getRuntime();
  11947. }
  11948. public IRubyObject call(ThreadContext context, IRubyObject[] iargs, Block block) {
  11949. this.block.call(context, new IRubyObject[] { runtime.newArray(iargs[0], runtime.newFixnum(index++)) });
  11950. return runtime.getNil();
  11951. }
  11952. }
  11953. @JRubyMethod(name = "each_with_index", frame = true)
  11954. public static IRubyObject each_with_index(ThreadContext context, IRubyObject self, Block block) {
  11955. RuntimeHelpers.invoke(context, self, "each", CallBlock.newCallClosure(self, self.getRuntime().getEnumerable(),
  11956. Arity.noArguments(), new EachWithIndex(context, block), context));
  11957. return self;
  11958. }
  11959. @JRubyMethod(name = {"include?", "member?"}, required = 1, frame = true)
  11960. public static IRubyObject include_p(ThreadContext context, IRubyObject self, final IRubyObject arg) {
  11961. final Ruby runtime = context.getRuntime();
  11962. final ThreadContext localContext = context;
  11963. try {
  11964. callEach(runtime, context, self, new BlockCallback() {
  11965. public IRubyObject call(ThreadContext ctx, IRubyObject[] largs, Block blk) {
  11966. if (localContext != ctx) {
  11967. throw runtime.newThreadError("Enumerable#include?/member? cannot be parallelized");
  11968. }
  11969. if (RubyObject.equalInternal(ctx, largs[0], arg)) {
  11970. throw JumpException.SPECIAL_JUMP;
  11971. }
  11972. return runtime.getNil();
  11973. }
  11974. });
  11975. } catch (JumpException.SpecialJump sj) {
  11976. return runtime.getTrue();
  11977. }
  11978. return runtime.getFalse();
  11979. }
  11980. @JRubyMethod(name = "max", frame = true)
  11981. public static IRubyObject max(ThreadContext context, IRubyObject self, final Block block) {
  11982. final Ruby runtime = self.getRuntime();
  11983. final IRubyObject result[] = new IRubyObject[] { null };
  11984. final ThreadContext localContext = context;
  11985. if (block.isGiven()) {
  11986. callEach(runtime, context, self, new BlockCallback() {
  11987. public IRubyObject call(ThreadContext ctx, IRubyObject[] largs, Block blk) {
  11988. if (localContext != ctx) {
  11989. throw runtime.newThreadError("Enumerable#max{} cannot be parallelized");
  11990. }
  11991. if (result[0] == null || RubyComparable.cmpint(ctx, block.yield(ctx,
  11992. runtime.newArray(largs[0], result[0])), largs[0], result[0]) > 0) {
  11993. result[0] = largs[0];
  11994. }
  11995. return runtime.getNil();
  11996. }
  11997. });
  11998. } else {
  11999. callEach(runtime, context, self, new BlockCallback() {
  12000. public IRubyObject call(ThreadContext ctx, IRubyObject[] largs, Block blk) {
  12001. synchronized (result) {
  12002. if (result[0] == null || RubyComparable.cmpint(ctx, largs[0].callMethod(ctx,
  12003. MethodIndex.OP_SPACESHIP, "<=>", result[0]), largs[0], result[0]) > 0) {
  12004. result[0] = largs[0];