Skip to content

Commit

Permalink
Merge branch 'master' into truffle-head
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisseaton committed Dec 10, 2014
2 parents b494d7c + b7a688e commit 81a4810
Show file tree
Hide file tree
Showing 34 changed files with 1,587 additions and 174 deletions.
69 changes: 69 additions & 0 deletions core/src/main/java/org/jruby/truffle/nodes/cast/ToSNode.java
@@ -0,0 +1,69 @@
/*
* Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.nodes.cast;

import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.UnexpectedResultException;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.RubyTypesGen;
import org.jruby.truffle.nodes.core.KernelNodes;
import org.jruby.truffle.nodes.core.KernelNodesFactory;
import org.jruby.truffle.nodes.dispatch.DispatchHeadNode;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubyString;

@NodeChild(type = RubyNode.class)
public abstract class ToSNode extends RubyNode {

@Child protected DispatchHeadNode callToSNode;
@Child protected KernelNodes.ClassNode classNode;
@Child protected KernelNodes.ToSNode toSNode;

public ToSNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
callToSNode = new DispatchHeadNode(context, true);
classNode = KernelNodesFactory.ClassNodeFactory.create(context, sourceSection, new RubyNode[]{null});
toSNode = KernelNodesFactory.ToSNodeFactory.create(context, sourceSection, new RubyNode[]{null});
}

public ToSNode(ToSNode prev) {
super(prev);
callToSNode = prev.callToSNode;
classNode = prev.classNode;
toSNode = prev.toSNode;
}

@Override
public abstract RubyString executeString(VirtualFrame frame);

@Specialization
public RubyString toS(RubyString string) {
return string;
}

@Specialization(guards = "!isRubyString", rewriteOn = UnexpectedResultException.class)
public RubyString toS(VirtualFrame frame, Object object) throws UnexpectedResultException {
return RubyTypesGen.RUBYTYPES.expectRubyString(callToSNode.call(frame, object, "to_s", null));
}

@Specialization(guards = "!isRubyString")
public RubyString toSFallback(VirtualFrame frame, Object object) {
final Object value = callToSNode.call(frame, object, "to_s", null);

if (value instanceof RubyString) {
return (RubyString) value;
} else {
return toSNode.toS(classNode.executeGetClass(frame, object));
}
}
}
Expand Up @@ -14,6 +14,7 @@
import com.oracle.truffle.api.frame.*;
import com.oracle.truffle.api.nodes.*;
import org.jruby.truffle.nodes.*;
import org.jruby.truffle.nodes.cast.ToSNode;
import org.jruby.truffle.nodes.dispatch.DispatchHeadNode;
import org.jruby.truffle.runtime.*;
import org.jruby.truffle.runtime.core.RubyBasicObject;
Expand All @@ -25,13 +26,11 @@
*/
public final class InterpolatedStringNode extends RubyNode {

@Children protected final RubyNode[] children;
@Child protected DispatchHeadNode toS;
@Children protected final ToSNode[] children;

public InterpolatedStringNode(RubyContext context, SourceSection sourceSection, RubyNode[] children) {
public InterpolatedStringNode(RubyContext context, SourceSection sourceSection, ToSNode[] children) {
super(context, sourceSection);
this.children = children;
toS = new DispatchHeadNode(context, true);
}

@ExplodeLoop
Expand All @@ -40,16 +39,7 @@ public Object execute(VirtualFrame frame) {
final RubyString[] strings = new RubyString[children.length];

for (int n = 0; n < children.length; n++) {
Object result = toS.call(frame, children[n].execute(frame), "to_s", null);

if (result instanceof RubyString) {
strings[n] = (RubyString) result;
} else if (result instanceof RubyBasicObject) {
strings[n] = KernelNodesFactory.ToSNodeFactory.create(getContext(), getSourceSection(), new RubyNode[]{}).toS((RubyBasicObject) result);
} else {
RubyBasicObject boxed = getContext().getCoreLibrary().getLogicalClass(result);
strings[n] = KernelNodesFactory.ToSNodeFactory.create(getContext(), getSourceSection(), new RubyNode[]{}).toS(boxed);
}
strings[n] = children[n].executeString(frame);
}

return concat(strings);
Expand Down
Expand Up @@ -362,6 +362,8 @@ public ClassNode(ClassNode prev) {
super(prev);
}

public abstract RubyClass executeGetClass(VirtualFrame frame, Object value);

@Specialization
public RubyClass getClass(boolean value) {
notDesignedForCompilation();
Expand Down
Expand Up @@ -702,13 +702,13 @@ public RubyNode visitDSymbolNode(org.jruby.ast.DSymbolNode node) {
}

private RubyNode translateInterpolatedString(SourceSection sourceSection, List<org.jruby.ast.Node> childNodes) {
final List<RubyNode> children = new ArrayList<>();
final List<ToSNode> children = new ArrayList<>();

for (org.jruby.ast.Node child : childNodes) {
children.add(child.accept(this));
children.add(ToSNodeFactory.create(context, sourceSection, child.accept(this)));
}

return new InterpolatedStringNode(context, sourceSection, children.toArray(new RubyNode[children.size()]));
return new InterpolatedStringNode(context, sourceSection, children.toArray(new ToSNode[children.size()]));
}

@Override
Expand Down
2 changes: 1 addition & 1 deletion default.build.properties
Expand Up @@ -38,7 +38,7 @@ version.ruby=2.2.0
version.ruby.major=2.2
version.ruby.minor=0
version.ruby.patchlevel=0
version.ruby.revision=48175
version.ruby.revision=48765

version.ruby1_9.major=1.9
version.ruby1_9=1.9.3
Expand Down
10 changes: 9 additions & 1 deletion lib/ruby/stdlib/csv.rb
Expand Up @@ -1470,7 +1470,15 @@ def self.table(path, options = Hash.new)
# if the data cannot be transcoded,
# leaving the header unchanged.
# <b><tt>:skip_blanks</tt></b>:: When set to a +true+ value, CSV will
# skip over any rows with no content.
# skip over any empty rows. Note that
# this setting will not skip rows that
# contain column separators, even if
# the rows contain no actual data. If
# you want to skip rows that contain
# separators but no content, consider
# using <tt>:skip_lines</tt>, or
# inspecting fields.compact.empty? on
# each row.
# <b><tt>:force_quotes</tt></b>:: When set to a +true+ value, CSV will
# quote all CSV fields it creates.
# <b><tt>:skip_lines</tt></b>:: When set to an object responding to
Expand Down
24 changes: 21 additions & 3 deletions lib/ruby/stdlib/digest.rb
@@ -1,6 +1,9 @@
require 'digest.so'

module Digest
# A mutex for Digest().
REQUIRE_MUTEX = Mutex.new

def self.const_missing(name) # :nodoc:
case name
when :SHA256, :SHA384, :SHA512
Expand Down Expand Up @@ -76,15 +79,30 @@ def base64digest!
# call-seq:
# Digest(name) -> digest_subclass
#
# Returns a Digest subclass by +name+.
# Returns a Digest subclass by +name+ in a thread-safe manner even
# when on-demand loading is involved.
#
# require 'digest'
#
# Digest("MD5")
# # => Digest::MD5
#
# Digest("Foo")
# Digest(:SHA256)
# # => Digest::SHA256
#
# Digest(:Foo)
# # => LoadError: library not found for class Digest::Foo -- digest/foo
def Digest(name)
Digest.const_get(name)
const = name.to_sym
Digest::REQUIRE_MUTEX.synchronize {
# Ignore autoload's because it is void when we have #const_missing
Digest.const_missing(const)
}
rescue LoadError
# Constants do not necessarily rely on digest/*.
if Digest.const_defined?(const)
Digest.const_get(const)
else
raise
end
end
115 changes: 104 additions & 11 deletions lib/ruby/stdlib/matrix.rb
Expand Up @@ -62,6 +62,7 @@ module ExceptionForMatrix # :nodoc:
# * #minor(*param)
# * #first_minor(row, column)
# * #cofactor(row, column)
# * #adjugate
# * #laplace_expansion(row_or_column: num)
# * #cofactor_expansion(row_or_column: num)
#
Expand Down Expand Up @@ -444,7 +445,7 @@ def collect(&block) # :yield: e

#
# Yields all elements of the matrix, starting with those of the first row,
# or returns an Enumerator is no block given.
# or returns an Enumerator if no block given.
# Elements can be restricted by passing an argument:
# * :all (default): yields all elements
# * :diagonal: yields only elements on the diagonal
Expand Down Expand Up @@ -689,6 +690,20 @@ def cofactor(row, column)
det_of_minor * (-1) ** (row + column)
end

#
# Returns the adjugate of the matrix.
#
# Matrix[ [7,6],[3,9] ].adjugate
# => 9 -6
# -3 7
#
def adjugate
Matrix.Raise ErrDimensionMismatch unless square?
Matrix.build(row_count, column_count) do |row, column|
cofactor(column, row)
end
end

#
# Returns the Laplace expansion along given row or column.
#
Expand Down Expand Up @@ -1676,6 +1691,11 @@ def ** (other)
# * #each2(v)
# * #collect2(v)
#
# Properties of vectors:
# * #angle_with(v)
# * Vector.independent?(*vs)
# * #independent?(*vs)
#
# Vector arithmetic:
# * #*(x) "is matrix or number"
# * #+(v)
Expand All @@ -1684,8 +1704,8 @@ def ** (other)
# * #-@
#
# Vector functions:
# * #inner_product(v)
# * #cross_product(v)
# * #inner_product(v), dot(v)
# * #cross_product(v), cross(v)
# * #collect
# * #magnitude
# * #map
Expand Down Expand Up @@ -1816,6 +1836,41 @@ def collect2(v) # :yield: e1, e2
end
end

#--
# PROPERTIES -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#++

#
# Returns +true+ iff all of vectors are linearly independent.
#
# Vector.independent?(Vector[1,0], Vector[0,1])
# => true
#
# Vector.independent?(Vector[1,2], Vector[2,4])
# => false
#
def Vector.independent?(*vs)
vs.each do |v|
raise TypeError, "expected Vector, got #{v.class}" unless v.is_a?(Vector)
Vector.Raise ErrDimensionMismatch unless v.size == vs.first.size
end
return false if vs.count > vs.first.size
Matrix[*vs].rank.eql?(vs.count)
end

#
# Returns +true+ iff all of vectors are linearly independent.
#
# Vector[1,0].independent?(Vector[0,1])
# => true
#
# Vector[1,2].independent?(Vector[2,4])
# => false
#
def independent?(*vs)
self.class.independent?(self, *vs)
end

#--
# COMPARING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#++
Expand All @@ -1834,14 +1889,14 @@ def eql?(other)
end

#
# Return a copy of the vector.
# Returns a copy of the vector.
#
def clone
self.class.elements(@elements)
end

#
# Return a hash-code for the vector.
# Returns a hash-code for the vector.
#
def hash
@elements.hash
Expand Down Expand Up @@ -1944,17 +1999,41 @@ def inner_product(v)
}
p
end
alias_method :dot, :inner_product

#
# Returns the cross product of this vector with the other.
# Returns the cross product of this vector with the others.
# Vector[1, 0, 0].cross_product Vector[0, 1, 0] => Vector[0, 0, 1]
#
def cross_product(v)
Vector.Raise ErrDimensionMismatch unless size == v.size && v.size == 3
Vector[ v[2]*@elements[1] - v[1]*@elements[2],
v[0]*@elements[2] - v[2]*@elements[0],
v[1]*@elements[0] - v[0]*@elements[1] ]
# It is generalized to other dimensions to return a vector perpendicular
# to the arguments.
# Vector[1, 2].cross_product # => Vector[-2, 1]
# Vector[1, 0, 0, 0].cross_product(
# Vector[0, 1, 0, 0],
# Vector[0, 0, 1, 0]
# ) #=> Vector[0, 0, 0, 1]
#
def cross_product(*vs)
raise ErrOperationNotDefined, "cross product is not defined on vectors of dimension #{size}" unless size >= 2
raise ArgumentError, "wrong number of arguments (#{vs.size} for #{size - 2})" unless vs.size == size - 2
vs.each do |v|
raise TypeError, "expected Vector, got #{v.class}" unless v.is_a? Vector
Vector.Raise ErrDimensionMismatch unless v.size == size
end
case size
when 2
Vector[-@elements[1], @elements[0]]
when 3
v = vs[0]
Vector[ v[2]*@elements[1] - v[1]*@elements[2],
v[0]*@elements[2] - v[2]*@elements[0],
v[1]*@elements[0] - v[0]*@elements[1] ]
else
rows = self, *vs, Array.new(size) {|i| Vector.basis(size: size, index: i) }
Matrix.rows(rows).laplace_expansion(row: size - 1)
end
end
alias_method :cross, :cross_product

#
# Like Array#collect.
Expand Down Expand Up @@ -1999,6 +2078,20 @@ def normalize
self / n
end

#
# Returns an angle with another vector. Result is within the [0...Math::PI].
# Vector[1,0].angle_with(Vector[0,1])
# # => Math::PI / 2
#
def angle_with(v)
raise TypeError, "Expected a Vector, got a #{v.class}" unless v.is_a?(Vector)
Vector.Raise ErrDimensionMismatch if size != v.size
prod = magnitude * v.magnitude
raise ZeroVectorError, "Can't get angle of zero vector" if prod == 0

Math.acos( inner_product(v) / prod )
end

#--
# CONVERTING
#++
Expand Down

0 comments on commit 81a4810

Please sign in to comment.