From ea50d0179c51d271c9fead299e9bf6dd06fe9689 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Fri, 9 Jan 2015 09:56:35 -0600 Subject: Update to latest code from JRuby master. --- ext/java/PsychEmitter.java | 88 +++++++--- ext/java/PsychLibrary.java | 39 +++-- ext/java/PsychParser.java | 401 +++++++++++++++++++++++--------------------- ext/java/PsychToRuby.java | 54 +++--- ext/java/PsychYamlTree.java | 17 +- 5 files changed, 345 insertions(+), 254 deletions(-) (limited to 'ext/java') diff --git a/ext/java/PsychEmitter.java b/ext/java/PsychEmitter.java index 2a28872..d9f3231 100644 --- a/ext/java/PsychEmitter.java +++ b/ext/java/PsychEmitter.java @@ -1,10 +1,10 @@ /***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 + * Version: EPL 1.0/GPL 2.0/LGPL 2.1 * - * The contents of this file are subject to the Common Public + * The contents of this file are subject to the Eclipse Public * License Version 1.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html + * the License at http://www.eclipse.org/legal/epl-v10.html * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or @@ -19,19 +19,21 @@ * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your + * use your version of this file under the terms of the EPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. + * the terms of any one of the EPL, the GPL or the LGPL. ***** END LICENSE BLOCK *****/ -package psych; +package org.jruby.ext.psych; import java.io.IOException; import java.io.OutputStreamWriter; -import java.util.Collections; +import java.nio.charset.Charset; import java.util.HashMap; import java.util.Map; + +import org.jcodings.Encoding; import org.jruby.Ruby; import org.jruby.RubyArray; import org.jruby.RubyClass; @@ -44,7 +46,6 @@ import org.jruby.runtime.ObjectAllocator; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.util.IOOutputStream; -import org.jruby.util.TypeConverter; import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.emitter.Emitter; import org.yaml.snakeyaml.emitter.EmitterException; @@ -61,11 +62,13 @@ import org.yaml.snakeyaml.events.SequenceEndEvent; import org.yaml.snakeyaml.events.SequenceStartEvent; import org.yaml.snakeyaml.events.StreamEndEvent; import org.yaml.snakeyaml.events.StreamStartEvent; + import static org.jruby.runtime.Visibility.*; public class PsychEmitter extends RubyObject { public static void initPsychEmitter(Ruby runtime, RubyModule psych) { - RubyClass psychEmitter = runtime.defineClassUnder("Emitter", runtime.getObject(), new ObjectAllocator() { + RubyClass psychHandler = runtime.defineClassUnder("Handler", runtime.getObject(), runtime.getObject().getAllocator(), psych); + RubyClass psychEmitter = runtime.defineClassUnder("Emitter", psychHandler, new ObjectAllocator() { public IRubyObject allocate(Ruby runtime, RubyClass klazz) { return new PsychEmitter(runtime, klazz); } @@ -82,7 +85,25 @@ public class PsychEmitter extends RubyObject { public IRubyObject initialize(ThreadContext context, IRubyObject io) { options = new DumperOptions(); options.setIndent(2); - emitter = new Emitter(new OutputStreamWriter(new IOOutputStream(io)), options); + + this.io = io; + + return context.nil; + } + + @JRubyMethod(visibility = PRIVATE) + public IRubyObject initialize(ThreadContext context, IRubyObject io, IRubyObject rbOptions) { + IRubyObject width = rbOptions.callMethod(context, "line_width"); + IRubyObject canonical = rbOptions.callMethod(context, "canonical"); + IRubyObject level = rbOptions.callMethod(context, "indentation"); + + options = new DumperOptions(); + + options.setCanonical(canonical.isTrue()); + options.setIndent((int)level.convertToInteger().getLongValue()); + options.setWidth((int)width.convertToInteger().getLongValue()); + + this.io = io; return context.nil; } @@ -92,10 +113,13 @@ public class PsychEmitter extends RubyObject { if (!(encoding instanceof RubyFixnum)) { throw context.runtime.newTypeError(encoding, context.runtime.getFixnum()); } - - // TODO: do something with encoding? perhaps at the stream level? + + initEmitter(context, encoding); + StreamStartEvent event = new StreamStartEvent(NULL_MARK, NULL_MARK); + emit(context, event); + return this; } @@ -107,16 +131,26 @@ public class PsychEmitter extends RubyObject { } @JRubyMethod - public IRubyObject start_document(ThreadContext context, IRubyObject version, IRubyObject tags, IRubyObject implicit) { - Integer[] versionInts = null; + public IRubyObject start_document(ThreadContext context, IRubyObject _version, IRubyObject tags, IRubyObject implicit) { + DumperOptions.Version version = null; boolean implicitBool = implicit.isTrue(); - Map tagsMap = Collections.EMPTY_MAP; + Map tagsMap = null; - RubyArray versionAry = version.convertToArray(); + RubyArray versionAry = _version.convertToArray(); if (versionAry.size() == 2) { - versionInts = new Integer[] {1, 1}; - versionInts[0] = (int)versionAry.eltInternal(0).convertToInteger().getLongValue(); - versionInts[1] = (int)versionAry.eltInternal(1).convertToInteger().getLongValue(); + int versionInt0 = (int)versionAry.eltInternal(0).convertToInteger().getLongValue(); + int versionInt1 = (int)versionAry.eltInternal(1).convertToInteger().getLongValue(); + + if (versionInt0 == 1) { + if (versionInt1 == 0) { + version = DumperOptions.Version.V1_0; + } else if (versionInt1 == 1) { + version = DumperOptions.Version.V1_1; + } + } + if (version == null) { + throw context.runtime.newArgumentError("invalid YAML version: " + versionAry); + } } RubyArray tagsAry = tags.convertToArray(); @@ -135,14 +169,14 @@ public class PsychEmitter extends RubyObject { } } - DocumentStartEvent event = new DocumentStartEvent(NULL_MARK, NULL_MARK, implicitBool, versionInts, tagsMap); + DocumentStartEvent event = new DocumentStartEvent(NULL_MARK, NULL_MARK, !implicitBool, version, tagsMap); emit(context, event); return this; } @JRubyMethod public IRubyObject end_document(ThreadContext context, IRubyObject implicit) { - DocumentEndEvent event = new DocumentEndEvent(NULL_MARK, NULL_MARK, implicit.isTrue()); + DocumentEndEvent event = new DocumentEndEvent(NULL_MARK, NULL_MARK, !implicit.isTrue()); emit(context, event); return this; } @@ -273,6 +307,8 @@ public class PsychEmitter extends RubyObject { private void emit(ThreadContext context, Event event) { try { + if (emitter == null) throw context.runtime.newRuntimeError("uninitialized emitter"); + emitter.emit(event); } catch (IOException ioe) { throw context.runtime.newIOErrorFromException(ioe); @@ -281,8 +317,18 @@ public class PsychEmitter extends RubyObject { } } + private void initEmitter(ThreadContext context, IRubyObject _encoding) { + if (emitter != null) throw context.runtime.newRuntimeError("already initialized emitter"); + + Encoding encoding = PsychLibrary.YAMLEncoding.values()[(int)_encoding.convertToInteger().getLongValue()].encoding; + Charset charset = context.runtime.getEncodingService().charsetForEncoding(encoding); + + emitter = new Emitter(new OutputStreamWriter(new IOOutputStream(io, encoding), charset), options); + } + Emitter emitter; DumperOptions options = new DumperOptions(); + IRubyObject io; private static final Mark NULL_MARK = new Mark(null, 0, 0, 0, null, 0); diff --git a/ext/java/PsychLibrary.java b/ext/java/PsychLibrary.java index 864a4f4..2d2141b 100644 --- a/ext/java/PsychLibrary.java +++ b/ext/java/PsychLibrary.java @@ -1,10 +1,10 @@ /***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 + * Version: EPL 1.0/GPL 2.0/LGPL 2.1 * - * The contents of this file are subject to the Common Public + * The contents of this file are subject to the Eclipse Public * License Version 1.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html + * the License at http://www.eclipse.org/legal/epl-v10.html * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or @@ -19,14 +19,18 @@ * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your + * use your version of this file under the terms of the EPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. + * the terms of any one of the EPL, the GPL or the LGPL. ***** END LICENSE BLOCK *****/ -package psych; +package org.jruby.ext.psych; +import org.jcodings.Encoding; +import org.jcodings.specific.UTF16BEEncoding; +import org.jcodings.specific.UTF16LEEncoding; +import org.jcodings.specific.UTF8Encoding; import org.jruby.Ruby; import org.jruby.RubyArray; import org.jruby.RubyModule; @@ -38,16 +42,18 @@ import org.jruby.runtime.builtin.IRubyObject; import org.jruby.runtime.load.Library; public class PsychLibrary implements Library { + // NOTE: we add the last .0 for format compat with libyaml version numbers + // TODO: This should always reflect the SnakeYAML version + private static final String SNAKEYAML_VERSION = "1.13.0"; public void load(final Ruby runtime, boolean wrap) { RubyModule psych = runtime.defineModule("Psych"); - RubyString version = runtime.newString("0.1.4"); + RubyString version = runtime.newString(SNAKEYAML_VERSION); version.setFrozen(true); - final RubyArray versionElements = runtime.newArray(runtime.newFixnum(0), runtime.newFixnum(1), runtime.newFixnum(4)); + final RubyArray versionElements = runtime.newArray(runtime.newFixnum(1), runtime.newFixnum(13), runtime.newFixnum(0)); versionElements.setFrozen(true); - - psych.setConstant("LIBYAML_VERSION", runtime.newString("0.1.4")); + psych.getSingletonClass().addMethod("libyaml_version", new JavaMethodZero(psych, Visibility.PUBLIC) { @Override public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name) { @@ -60,4 +66,17 @@ public class PsychLibrary implements Library { PsychToRuby.initPsychToRuby(runtime, psych); PsychYamlTree.initPsychYamlTree(runtime, psych); } + + public enum YAMLEncoding { + YAML_ANY_ENCODING(UTF8Encoding.INSTANCE), + YAML_UTF8_ENCODING(UTF8Encoding.INSTANCE), + YAML_UTF16LE_ENCODING(UTF16LEEncoding.INSTANCE), + YAML_UTF16BE_ENCODING(UTF16BEEncoding.INSTANCE); + + YAMLEncoding(Encoding encoding) { + this.encoding = encoding; + } + + public final Encoding encoding; + } } diff --git a/ext/java/PsychParser.java b/ext/java/PsychParser.java index 25d8636..6bb7612 100644 --- a/ext/java/PsychParser.java +++ b/ext/java/PsychParser.java @@ -1,10 +1,10 @@ /***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 + * Version: EPL 1.0/GPL 2.0/LGPL 2.1 * - * The contents of this file are subject to the Common Public + * The contents of this file are subject to the Eclipse Public * License Version 1.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html + * the License at http://www.eclipse.org/legal/epl-v10.html * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or @@ -19,37 +19,41 @@ * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your + * use your version of this file under the terms of the EPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. + * the terms of any one of the EPL, the GPL or the LGPL. ***** END LICENSE BLOCK *****/ -package psych; +package org.jruby.ext.psych; +import java.io.ByteArrayInputStream; import java.io.InputStreamReader; -import java.io.StringReader; +import java.nio.charset.Charset; import java.util.Map; -import org.jcodings.specific.UTF16BEEncoding; -import org.jcodings.specific.UTF16LEEncoding; + +import org.jcodings.Encoding; import org.jcodings.specific.UTF8Encoding; import org.jruby.Ruby; import org.jruby.RubyArray; import org.jruby.RubyClass; import org.jruby.RubyEncoding; -import org.jruby.RubyException; import org.jruby.RubyIO; import org.jruby.RubyKernel; import org.jruby.RubyModule; import org.jruby.RubyObject; import org.jruby.RubyString; import org.jruby.anno.JRubyMethod; +import static org.jruby.ext.psych.PsychLibrary.YAMLEncoding.*; import org.jruby.runtime.Block; +import org.jruby.runtime.Helpers; import org.jruby.runtime.ObjectAllocator; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.util.IOInputStream; -import org.jruby.util.unsafe.UnsafeFactory; +import org.jruby.util.log.Logger; +import org.jruby.util.log.LoggerFactory; +import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.error.Mark; import org.yaml.snakeyaml.error.MarkedYAMLException; import org.yaml.snakeyaml.events.AliasEvent; @@ -66,14 +70,12 @@ import org.yaml.snakeyaml.parser.ParserImpl; import org.yaml.snakeyaml.reader.ReaderException; import org.yaml.snakeyaml.reader.StreamReader; import org.yaml.snakeyaml.scanner.ScannerException; -import static org.jruby.javasupport.util.RuntimeHelpers.invoke; +import static org.jruby.runtime.Helpers.invoke; +import org.jruby.util.ByteList; public class PsychParser extends RubyObject { - public static final int YAML_ANY_ENCODING = 0; - public static final int YAML_UTF8_ENCODING = UTF8Encoding.INSTANCE.getIndex(); - public static final int YAML_UTF16LE_ENCODING = UTF16LEEncoding.INSTANCE.getIndex(); - public static final int YAML_UTF16BE_ENCODING = UTF16BEEncoding.INSTANCE.getIndex(); + private static final Logger LOG = LoggerFactory.getLogger("PsychParser"); public static void initPsychParser(Ruby runtime, RubyModule psych) { RubyClass psychParser = runtime.defineClassUnder("Parser", runtime.getObject(), new ObjectAllocator() { @@ -82,14 +84,14 @@ public class PsychParser extends RubyObject { } }, psych); - psychParser.defineConstant("ANY", runtime.newFixnum(YAML_ANY_ENCODING)); - psychParser.defineConstant("UTF8", runtime.newFixnum(YAML_UTF8_ENCODING)); - psychParser.defineConstant("UTF16LE", runtime.newFixnum(YAML_UTF16LE_ENCODING)); - psychParser.defineConstant("UTF16BE", runtime.newFixnum(YAML_UTF16BE_ENCODING)); + RubyKernel.require(runtime.getNil(), + runtime.newString("psych/syntax_error"), Block.NULL_BLOCK); + psychParser.defineConstant("ANY", runtime.newFixnum(YAML_ANY_ENCODING.ordinal())); + psychParser.defineConstant("UTF8", runtime.newFixnum(YAML_UTF8_ENCODING.ordinal())); + psychParser.defineConstant("UTF16LE", runtime.newFixnum(YAML_UTF16LE_ENCODING.ordinal())); + psychParser.defineConstant("UTF16BE", runtime.newFixnum(YAML_UTF16BE_ENCODING.ordinal())); psychParser.defineAnnotatedMethods(PsychParser.class); - - psych.defineClassUnder("SyntaxError", runtime.getSyntaxError(), RubyException.EXCEPTION_ALLOCATOR); } public PsychParser(Ruby runtime, RubyClass klass) { @@ -100,26 +102,72 @@ public class PsychParser extends RubyObject { public IRubyObject parse(ThreadContext context, IRubyObject yaml) { Ruby runtime = context.runtime; - return parse(context, yaml, RubyString.newString(runtime, "")); + return parse(context, yaml, runtime.getNil()); + } + + private IRubyObject stringOrNilFor(Ruby runtime, String value, boolean tainted) { + if (value == null) return runtime.getNil(); // No need to taint nil + + return stringFor(runtime, value, tainted); + } + + private RubyString stringFor(Ruby runtime, String value, boolean tainted) { + Encoding encoding = runtime.getDefaultInternalEncoding(); + if (encoding == null) { + encoding = UTF8Encoding.INSTANCE; + } + + Charset charset = RubyEncoding.UTF8; + if (encoding.getCharset() != null) { + charset = encoding.getCharset(); + } + + ByteList bytes = new ByteList(value.getBytes(charset), encoding); + RubyString string = RubyString.newString(runtime, bytes); + + string.setTaint(tainted); + + return string; + } + + private StreamReader readerFor(ThreadContext context, IRubyObject yaml) { + Ruby runtime = context.runtime; + + if (yaml instanceof RubyString) { + ByteList byteList = ((RubyString)yaml).getByteList(); + ByteArrayInputStream bais = new ByteArrayInputStream(byteList.getUnsafeBytes(), byteList.getBegin(), byteList.getRealSize()); + + Charset charset = byteList.getEncoding().getCharset(); + if (charset == null) charset = Charset.defaultCharset(); + + InputStreamReader isr = new InputStreamReader(bais, charset); + + return new StreamReader(isr); + } + + // fall back on IOInputStream, using default charset + if (yaml.respondsTo("read")) { + Charset charset = (yaml instanceof RubyIO) + ? ((RubyIO)yaml).getReadEncoding().getCharset() + : Charset.defaultCharset(); + return new StreamReader(new InputStreamReader(new IOInputStream(yaml), charset)); + } else { + throw runtime.newTypeError(yaml, runtime.getIO()); + } } @JRubyMethod public IRubyObject parse(ThreadContext context, IRubyObject yaml, IRubyObject path) { Ruby runtime = context.runtime; - boolean tainted = yaml.isTaint(); - - // FIXME? only supports Unicode, since we have to produces strings... + boolean tainted = yaml.isTaint() || yaml instanceof RubyIO; + try { - StreamReader reader; - if (yaml.respondsTo("read")) { - reader = new StreamReader(new InputStreamReader(new IOInputStream(yaml), RubyEncoding.UTF8)); - if (yaml instanceof RubyIO) { - tainted = true; - } - } else { - reader = new StreamReader(new StringReader(yaml.convertToString().asJavaString())); + parser = new ParserImpl(readerFor(context, yaml)); + + if (path.isNil() && yaml.respondsTo("path")) { + path = yaml.callMethod(context, "path"); } - parser = new ParserImpl(reader); + IRubyObject handler = getInstanceVariable("@handler"); while (true) { @@ -127,184 +175,158 @@ public class PsychParser extends RubyObject { // FIXME: Event should expose a getID, so it can be switched if (event.is(ID.StreamStart)) { - invoke( - context, - handler, - "start_stream", - runtime.newFixnum(YAML_ANY_ENCODING)); + invoke(context, handler, "start_stream", runtime.newFixnum(YAML_ANY_ENCODING.ordinal())); } else if (event.is(ID.DocumentStart)) { - DocumentStartEvent dse = (DocumentStartEvent)event; - - Integer[] versionInts = dse.getVersion(); - IRubyObject version = versionInts == null ? - RubyArray.newArray(runtime) : - RubyArray.newArray(runtime, runtime.newFixnum(versionInts[0]), runtime.newFixnum(versionInts[1])); - - Map tagsMap = dse.getTags(); - RubyArray tags = RubyArray.newArray(runtime); - if (tags.size() > 0) { - for (Map.Entry tag : tagsMap.entrySet()) { - RubyString key = RubyString.newString(runtime, tag.getKey()); - RubyString value = RubyString.newString(runtime, tag.getValue()); - key.setTaint(tainted); - value.setTaint(tainted); - - tags.append(RubyArray.newArray( - runtime, - key, - value)); - } - } - - invoke( - context, - handler, - "start_document", - version, - tags, - runtime.newBoolean(!dse.getExplicit())); + handleDocumentStart(context, (DocumentStartEvent) event, tainted, handler); } else if (event.is(ID.DocumentEnd)) { - DocumentEndEvent dee = (DocumentEndEvent)event; - invoke( - context, - handler, - "end_document", - runtime.newBoolean(!dee.getExplicit())); + IRubyObject notExplicit = runtime.newBoolean(!((DocumentEndEvent) event).getExplicit()); + + invoke(context, handler, "end_document", notExplicit); } else if (event.is(ID.Alias)) { - AliasEvent ae = (AliasEvent)event; - IRubyObject alias = runtime.getNil(); - if (ae.getAnchor() != null) { - alias = RubyString.newString(runtime, ae.getAnchor()); - alias.setTaint(tainted); - } - - invoke( - context, - handler, - "alias", - alias); + IRubyObject alias = stringOrNilFor(runtime, ((AliasEvent)event).getAnchor(), tainted); + + invoke(context, handler, "alias", alias); } else if (event.is(ID.Scalar)) { - ScalarEvent se = (ScalarEvent)event; - IRubyObject anchor = se.getAnchor() == null ? - runtime.getNil() : - RubyString.newString(runtime, se.getAnchor()); - IRubyObject tag = se.getTag() == null ? - runtime.getNil() : - RubyString.newString(runtime, se.getTag()); - IRubyObject plain_implicit = runtime.newBoolean(se.getImplicit().canOmitTagInPlainScalar()); - IRubyObject quoted_implicit = runtime.newBoolean(se.getImplicit().canOmitTagInNonPlainScalar()); - IRubyObject style = runtime.newFixnum(translateStyle(se.getStyle())); - IRubyObject val = RubyString.newString(runtime, se.getValue()); - - val.setTaint(tainted); - anchor.setTaint(tainted); - tag.setTaint(tainted); - - invoke( - context, - handler, - "scalar", - val, - anchor, - tag, - plain_implicit, - quoted_implicit, - style); + handleScalar(context, (ScalarEvent) event, tainted, handler); } else if (event.is(ID.SequenceStart)) { - SequenceStartEvent sse = (SequenceStartEvent)event; - IRubyObject anchor = sse.getAnchor() == null ? - runtime.getNil() : - RubyString.newString(runtime, sse.getAnchor()); - IRubyObject tag = sse.getTag() == null ? - runtime.getNil() : - RubyString.newString(runtime, sse.getTag()); - IRubyObject implicit = runtime.newBoolean(sse.getImplicit()); - IRubyObject style = runtime.newFixnum(translateFlowStyle(sse.getFlowStyle())); - - anchor.setTaint(tainted); - tag.setTaint(tainted); - - invoke( - context, - handler, - "start_sequence", - anchor, - tag, - implicit, - style); + handleSequenceStart(context,(SequenceStartEvent) event, tainted, handler); } else if (event.is(ID.SequenceEnd)) { - invoke( - context, - handler, - "end_sequence"); + invoke(context, handler, "end_sequence"); } else if (event.is(ID.MappingStart)) { - MappingStartEvent mse = (MappingStartEvent)event; - IRubyObject anchor = mse.getAnchor() == null ? - runtime.getNil() : - RubyString.newString(runtime, mse.getAnchor()); - IRubyObject tag = mse.getTag() == null ? - runtime.getNil() : - RubyString.newString(runtime, mse.getTag()); - IRubyObject implicit = runtime.newBoolean(mse.getImplicit()); - IRubyObject style = runtime.newFixnum(translateFlowStyle(mse.getFlowStyle())); - - anchor.setTaint(tainted); - tag.setTaint(tainted); - - invoke( - context, - handler, - "start_mapping", - anchor, - tag, - implicit, - style); + handleMappingStart(context, (MappingStartEvent) event, tainted, handler); } else if (event.is(ID.MappingEnd)) { - invoke( - context, - handler, - "end_mapping"); + invoke(context, handler, "end_mapping"); } else if (event.is(ID.StreamEnd)) { - invoke( - context, - handler, - "end_stream"); + invoke(context, handler, "end_stream"); + break; } } } catch (ParserException pe) { parser = null; - RubyKernel.raise(context, runtime.getKernel(), - new IRubyObject[] {runtime.getModule("Psych").getConstant("SyntaxError"), runtime.newString(syntaxError(context, yaml, pe))}, - Block.NULL_BLOCK); + raiseParserException(context, yaml, pe, path); + } catch (ScannerException se) { parser = null; StringBuilder message = new StringBuilder("syntax error"); if (se.getProblemMark() != null) { message.append(se.getProblemMark().toString()); } - throw runtime.newArgumentError(message.toString()); + raiseParserException(context, yaml, se, path); + } catch (ReaderException re) { parser = null; - RubyKernel.raise(context, runtime.getKernel(), - new IRubyObject[] {runtime.getModule("Psych").getConstant("SyntaxError"), runtime.newString(re.getLocalizedMessage())}, - Block.NULL_BLOCK); + raiseParserException(context, yaml, re, path); + } catch (Throwable t) { - UnsafeFactory.getUnsafe().throwException(t); + Helpers.throwException(t); return this; } return this; } - - private static String syntaxError(ThreadContext context, IRubyObject yaml, MarkedYAMLException mye) { - String path; - if (yaml.respondsTo("path")) { - path = yaml.callMethod(context, "path").toString(); - } else { - path = ""; + + private void handleDocumentStart(ThreadContext context, DocumentStartEvent dse, boolean tainted, IRubyObject handler) { + Ruby runtime = context.runtime; + DumperOptions.Version _version = dse.getVersion(); + Integer[] versionInts = _version == null ? null : _version.getArray(); + IRubyObject version = versionInts == null ? + RubyArray.newArray(runtime) : + RubyArray.newArray(runtime, runtime.newFixnum(versionInts[0]), runtime.newFixnum(versionInts[1])); + + Map tagsMap = dse.getTags(); + RubyArray tags = RubyArray.newArray(runtime); + if (tagsMap != null && tagsMap.size() > 0) { + for (Map.Entry tag : tagsMap.entrySet()) { + IRubyObject key = stringFor(runtime, tag.getKey(), tainted); + IRubyObject value = stringFor(runtime, tag.getValue(), tainted); + + tags.append(RubyArray.newArray(runtime, key, value)); + } } - return path + ": couldn't parse YAML at line " + mye.getProblemMark().getLine() + " column " + mye.getProblemMark().getColumn(); + IRubyObject notExplicit = runtime.newBoolean(!dse.getExplicit()); + + invoke(context, handler, "start_document", version, tags, notExplicit); + } + + private void handleMappingStart(ThreadContext context, MappingStartEvent mse, boolean tainted, IRubyObject handler) { + Ruby runtime = context.runtime; + IRubyObject anchor = stringOrNilFor(runtime, mse.getAnchor(), tainted); + IRubyObject tag = stringOrNilFor(runtime, mse.getTag(), tainted); + IRubyObject implicit = runtime.newBoolean(mse.getImplicit()); + IRubyObject style = runtime.newFixnum(translateFlowStyle(mse.getFlowStyle())); + + invoke(context, handler, "start_mapping", anchor, tag, implicit, style); + } + + private void handleScalar(ThreadContext context, ScalarEvent se, boolean tainted, IRubyObject handler) { + Ruby runtime = context.runtime; + IRubyObject anchor = stringOrNilFor(runtime, se.getAnchor(), tainted); + IRubyObject tag = stringOrNilFor(runtime, se.getTag(), tainted); + IRubyObject plain_implicit = runtime.newBoolean(se.getImplicit().canOmitTagInPlainScalar()); + IRubyObject quoted_implicit = runtime.newBoolean(se.getImplicit().canOmitTagInNonPlainScalar()); + IRubyObject style = runtime.newFixnum(translateStyle(se.getStyle())); + IRubyObject val = stringFor(runtime, se.getValue(), tainted); + + invoke(context, handler, "scalar", val, anchor, tag, plain_implicit, + quoted_implicit, style); + } + + private void handleSequenceStart(ThreadContext context, SequenceStartEvent sse, boolean tainted, IRubyObject handler) { + Ruby runtime = context.runtime; + IRubyObject anchor = stringOrNilFor(runtime, sse.getAnchor(), tainted); + IRubyObject tag = stringOrNilFor(runtime, sse.getTag(), tainted); + IRubyObject implicit = runtime.newBoolean(sse.getImplicit()); + IRubyObject style = runtime.newFixnum(translateFlowStyle(sse.getFlowStyle())); + + invoke(context, handler, "start_sequence", anchor, tag, implicit, style); + } + + private static void raiseParserException(ThreadContext context, IRubyObject yaml, ReaderException re, IRubyObject rbPath) { + Ruby runtime; + RubyClass se; + IRubyObject exception; + + runtime = context.runtime; + se = (RubyClass)runtime.getModule("Psych").getConstant("SyntaxError"); + + exception = se.newInstance(context, + new IRubyObject[] { + rbPath, + runtime.newFixnum(0), + runtime.newFixnum(0), + runtime.newFixnum(re.getPosition()), + (null == re.getName() ? runtime.getNil() : runtime.newString(re.getName())), + (null == re.toString() ? runtime.getNil() : runtime.newString(re.toString())) + }, + Block.NULL_BLOCK); + + RubyKernel.raise(context, runtime.getKernel(), new IRubyObject[] { exception }, Block.NULL_BLOCK); + } + + private static void raiseParserException(ThreadContext context, IRubyObject yaml, MarkedYAMLException mye, IRubyObject rbPath) { + Ruby runtime; + Mark mark; + RubyClass se; + IRubyObject exception; + + runtime = context.runtime; + se = (RubyClass)runtime.getModule("Psych").getConstant("SyntaxError"); + + mark = mye.getProblemMark(); + + exception = se.newInstance(context, + new IRubyObject[] { + rbPath, + runtime.newFixnum(mark.getLine() + 1), + runtime.newFixnum(mark.getColumn() + 1), + runtime.newFixnum(mark.getIndex()), + (null == mye.getProblem() ? runtime.getNil() : runtime.newString(mye.getProblem())), + (null == mye.getContext() ? runtime.getNil() : runtime.newString(mye.getContext())) + }, + Block.NULL_BLOCK); + + RubyKernel.raise(context, runtime.getKernel(), new IRubyObject[] { exception }, Block.NULL_BLOCK); } private static int translateStyle(Character style) { @@ -335,9 +357,8 @@ public class PsychParser extends RubyObject { if (parser != null) { event = parser.peekEvent(); - if (event == null) { - event = this.event; - } + + if (event == null) event = this.event; } if (event == null) { @@ -361,12 +382,6 @@ public class PsychParser extends RubyObject { ); } - @JRubyMethod(name = "external_encoding=") - public IRubyObject external_encoding_set(ThreadContext context, IRubyObject encoding) { - // stubbed - return encoding; - } - private Parser parser; private Event event; } diff --git a/ext/java/PsychToRuby.java b/ext/java/PsychToRuby.java index c60a913..39f7c42 100644 --- a/ext/java/PsychToRuby.java +++ b/ext/java/PsychToRuby.java @@ -1,10 +1,10 @@ /***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 + * Version: EPL 1.0/GPL 2.0/LGPL 2.1 * - * The contents of this file are subject to the Common Public + * The contents of this file are subject to the Eclipse Public * License Version 1.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html + * the License at http://www.eclipse.org/legal/epl-v10.html * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or @@ -19,18 +19,19 @@ * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your + * use your version of this file under the terms of the EPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. + * the terms of any one of the EPL, the GPL or the LGPL. ***** END LICENSE BLOCK *****/ -package psych; +package org.jruby.ext.psych; import org.jruby.Ruby; import org.jruby.RubyClass; import org.jruby.RubyModule; import org.jruby.RubyObject; +import org.jruby.RubyException; import org.jruby.anno.JRubyMethod; import org.jruby.exceptions.RaiseException; import org.jruby.runtime.ThreadContext; @@ -39,33 +40,40 @@ import static org.jruby.runtime.Visibility.*; public class PsychToRuby { public static void initPsychToRuby(Ruby runtime, RubyModule psych) { + RubyClass classLoader = runtime.defineClassUnder("ClassLoader", runtime.getObject(), RubyObject.OBJECT_ALLOCATOR, psych); + RubyModule visitors = runtime.defineModuleUnder("Visitors", psych); RubyClass visitor = runtime.defineClassUnder("Visitor", runtime.getObject(), runtime.getObject().getAllocator(), visitors); RubyClass psychToRuby = runtime.defineClassUnder("ToRuby", visitor, RubyObject.OBJECT_ALLOCATOR, visitors); - psychToRuby.defineAnnotatedMethods(PsychToRuby.class); + psychToRuby.defineAnnotatedMethods(ToRuby.class); + classLoader.defineAnnotatedMethods(ClassLoader.class); } - @JRubyMethod(visibility = PRIVATE) - public static IRubyObject build_exception(ThreadContext context, IRubyObject self, IRubyObject klass, IRubyObject message) { - if (klass instanceof RubyClass) { - IRubyObject exception = ((RubyClass)klass).allocate(); - exception.getInternalVariables().setInternalVariable("mesg", message); - return exception; - } else { - throw context.runtime.newTypeError(klass, context.runtime.getClassClass()); + public static class ToRuby { + @JRubyMethod(visibility = PRIVATE) + public static IRubyObject build_exception(ThreadContext context, IRubyObject self, IRubyObject klass, IRubyObject message) { + if (klass instanceof RubyClass) { + IRubyObject exception = ((RubyClass)klass).allocate(); + ((RubyException)exception).message = message; + return exception; + } else { + throw context.runtime.newTypeError(klass, context.runtime.getClassClass()); + } } } - @JRubyMethod(visibility = PRIVATE) - public static IRubyObject path2class(ThreadContext context, IRubyObject self, IRubyObject path) { - try { - return context.runtime.getClassFromPath(path.asJavaString()); - } catch (RaiseException re) { - if (re.getException().getMetaClass() == context.runtime.getNameError()) { - throw context.runtime.newArgumentError("undefined class/module " + path); + public static class ClassLoader { + @JRubyMethod(visibility = PRIVATE) + public static IRubyObject path2class(ThreadContext context, IRubyObject self, IRubyObject path) { + try { + return context.runtime.getClassFromPath(path.asJavaString()); + } catch (RaiseException re) { + if (re.getException().getMetaClass() == context.runtime.getNameError()) { + throw context.runtime.newArgumentError("undefined class/module " + path); + } + throw re; } - throw re; } } } diff --git a/ext/java/PsychYamlTree.java b/ext/java/PsychYamlTree.java index d22148b..fdd16df 100644 --- a/ext/java/PsychYamlTree.java +++ b/ext/java/PsychYamlTree.java @@ -1,10 +1,10 @@ /***** BEGIN LICENSE BLOCK ***** - * Version: CPL 1.0/GPL 2.0/LGPL 2.1 + * Version: EPL 1.0/GPL 2.0/LGPL 2.1 * - * The contents of this file are subject to the Common Public + * The contents of this file are subject to the Eclipse Public * License Version 1.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of - * the License at http://www.eclipse.org/legal/cpl-v10.html + * the License at http://www.eclipse.org/legal/epl-v10.html * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or @@ -19,13 +19,13 @@ * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the CPL, indicate your + * use your version of this file under the terms of the EPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under - * the terms of any one of the CPL, the GPL or the LGPL. + * the terms of any one of the EPL, the GPL or the LGPL. ***** END LICENSE BLOCK *****/ -package psych; +package org.jruby.ext.psych; import org.jruby.Ruby; import org.jruby.RubyClass; @@ -47,6 +47,9 @@ public class PsychYamlTree { @JRubyMethod(visibility = PRIVATE) public static IRubyObject private_iv_get(ThreadContext context, IRubyObject self, IRubyObject target, IRubyObject prop) { - return target.getInstanceVariables().getInstanceVariable(prop.asJavaString()); + IRubyObject obj = (IRubyObject)target.getInternalVariables().getInternalVariable(prop.asJavaString()); + if (obj == null) obj = context.nil; + + return obj; } } -- cgit v1.2.3