Skip to content

Commit

Permalink
Showing 22 changed files with 1,268 additions and 140 deletions.
5 changes: 0 additions & 5 deletions spec/truffle/tags/core/file/constants/constants_tags.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
fails:File::Constants::APPEND is defined
fails:File::Constants::CREAT is defined
fails:File::Constants::EXCL is defined
fails:File::Constants::FNM_CASEFOLD is defined
fails:File::Constants::FNM_DOTMATCH is defined
fails:File::Constants::FNM_NOESCAPE is defined
fails:File::Constants::FNM_PATHNAME is defined
fails:File::Constants::FNM_SYSCASE is defined
fails:File::Constants::LOCK_EX is defined
fails:File::Constants::LOCK_NB is defined
@@ -18,4 +14,3 @@ fails:File::Constants::WRONLY is defined
fails:File::Constants::NOCTTY is defined
fails:File::Constants::SYNC is defined
fails(windows):File::Constants::BINARY is defined
fails:File::Constants::FNM_EXTGLOB is defined
1 change: 0 additions & 1 deletion spec/truffle/tags/core/file/constants_tags.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
fails:File::Constants matches mode constants
fails:File::Constants lock mode constants
fails:File::Constants File::LOCK_EX
fails:File::Constants File::LOCK_NB
1 change: 0 additions & 1 deletion spec/truffle/tags/core/file/file_tags.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
fails:File includes File::Constants
windows:File.file? returns true if the named file exists and is a regular file.
windows:File.file? raises an ArgumentError if not passed one argument
windows:File.file? raises a TypeError if not passed a String type
45 changes: 0 additions & 45 deletions spec/truffle/tags/core/file/fnmatch_tags.txt
Original file line number Diff line number Diff line change
@@ -1,68 +1,23 @@
fails:File.fnmatch matches entire strings
fails:File.fnmatch does not match partial strings
fails:File.fnmatch does not support { } patterns by default
fails:File.fnmatch supports some { } patterns when File::FNM_EXTGLOB is passed
fails:File.fnmatch doesn't support some { } patterns even when File::FNM_EXTGLOB is passed
fails:File.fnmatch doesn't match an extra } when File::FNM_EXTGLOB is passed
fails:File.fnmatch matches when both FNM_EXTGLOB and FNM_PATHNAME are passed
fails:File.fnmatch matches a single character for each ? character
fails:File.fnmatch matches zero or more characters for each * character
fails:File.fnmatch matches ranges of characters using bracket expresions (e.g. [a-z])
fails:File.fnmatch matches ranges of characters using bracket expresions, taking case into account
fails:File.fnmatch does not match characters outside of the range of the bracket expresion
fails:File.fnmatch matches ranges of characters using exclusive bracket expresions (e.g. [^t] or [!t])
fails:File.fnmatch matches characters with a case sensitive comparison
fails:File.fnmatch matches characters with case insensitive comparison when flags includes FNM_CASEFOLD
fails:File.fnmatch doesn't match case sensitive characters on platfroms with case sensitive paths, when flags include FNM_SYSCASE
fails:File.fnmatch does not match '/' characters with ? or * when flags includes FNM_PATHNAME
fails:File.fnmatch does not match '/' characters inside bracket expressions when flags includes FNM_PATHNAME
fails:File.fnmatch matches literal ? or * in path when pattern includes \? or \*
fails:File.fnmatch matches literal character (e.g. 'a') in path when pattern includes escaped character (e.g. \a)
fails:File.fnmatch matches '\' characters in path when flags includes FNM_NOESACPE
fails:File.fnmatch escapes special characters inside bracket expression
fails:File.fnmatch does not match leading periods in filenames with wildcards by default
fails:File.fnmatch matches patterns with leading periods to dotfiles by default
fails:File.fnmatch matches leading periods in filenames when flags includes FNM_DOTMATCH
fails:File.fnmatch matches multiple directories with ** and *
fails:File.fnmatch matches multiple directories with ** when flags includes File::FNM_PATHNAME
fails:File.fnmatch returns false if '/' in pattern do not match '/' in path when flags includes FNM_PATHNAME
fails:File.fnmatch returns true if '/' in pattern match '/' in path when flags includes FNM_PATHNAME
fails:File.fnmatch accepts an object that has a #to_path method
fails:File.fnmatch raises a TypeError if the first and second arguments are not string-like
fails:File.fnmatch raises a TypeError if the third argument is not an Integer
fails:File.fnmatch does not raise a TypeError if the third argument can be coerced to an Integer
fails:File.fnmatch? matches entire strings
fails:File.fnmatch? does not match partial strings
fails:File.fnmatch? does not support { } patterns by default
fails:File.fnmatch? supports some { } patterns when File::FNM_EXTGLOB is passed
fails:File.fnmatch? doesn't support some { } patterns even when File::FNM_EXTGLOB is passed
fails:File.fnmatch? doesn't match an extra } when File::FNM_EXTGLOB is passed
fails:File.fnmatch? matches when both FNM_EXTGLOB and FNM_PATHNAME are passed
fails:File.fnmatch? matches a single character for each ? character
fails:File.fnmatch? matches zero or more characters for each * character
fails:File.fnmatch? matches ranges of characters using bracket expresions (e.g. [a-z])
fails:File.fnmatch? matches ranges of characters using bracket expresions, taking case into account
fails:File.fnmatch? does not match characters outside of the range of the bracket expresion
fails:File.fnmatch? matches ranges of characters using exclusive bracket expresions (e.g. [^t] or [!t])
fails:File.fnmatch? matches characters with a case sensitive comparison
fails:File.fnmatch? matches characters with case insensitive comparison when flags includes FNM_CASEFOLD
fails:File.fnmatch? doesn't match case sensitive characters on platfroms with case sensitive paths, when flags include FNM_SYSCASE
fails:File.fnmatch? does not match '/' characters with ? or * when flags includes FNM_PATHNAME
fails:File.fnmatch? does not match '/' characters inside bracket expressions when flags includes FNM_PATHNAME
fails:File.fnmatch? matches literal ? or * in path when pattern includes \? or \*
fails:File.fnmatch? matches literal character (e.g. 'a') in path when pattern includes escaped character (e.g. \a)
fails:File.fnmatch? matches '\' characters in path when flags includes FNM_NOESACPE
fails:File.fnmatch? escapes special characters inside bracket expression
fails:File.fnmatch? does not match leading periods in filenames with wildcards by default
fails:File.fnmatch? matches patterns with leading periods to dotfiles by default
fails:File.fnmatch? matches leading periods in filenames when flags includes FNM_DOTMATCH
fails:File.fnmatch? matches multiple directories with ** and *
fails:File.fnmatch? matches multiple directories with ** when flags includes File::FNM_PATHNAME
fails:File.fnmatch? returns false if '/' in pattern do not match '/' in path when flags includes FNM_PATHNAME
fails:File.fnmatch? returns true if '/' in pattern match '/' in path when flags includes FNM_PATHNAME
fails:File.fnmatch? accepts an object that has a #to_path method
fails:File.fnmatch? raises a TypeError if the first and second arguments are not string-like
fails:File.fnmatch? raises a TypeError if the third argument is not an Integer
fails:File.fnmatch? does not raise a TypeError if the third argument can be coerced to an Integer
fails(windows):File.fnmatch matches case sensitive characters on platfroms with case insensitive paths, when flags include FNM_SYSCASE
fails(windows):File.fnmatch? matches case sensitive characters on platfroms with case insensitive paths, when flags include FNM_SYSCASE
1 change: 0 additions & 1 deletion spec/truffle/tags/core/file/lchown_tags.txt

This file was deleted.

2 changes: 0 additions & 2 deletions spec/truffle/tags/core/file/open_tags.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
fails:File.open opens the file (basic case)
fails:File.open opens a file when called with a block
fails:File.open opens with mode string
fails:File.open opens a file with mode num
fails:File.open opens a file with mode and permission as nil
@@ -51,7 +50,6 @@ fails:File.open opens a file for binary write
fails:File.open opens a file for read-write and truncate the file
fails:File.open opens a file for binary read-write starting at the beginning of the file
fails:File.open opens a file for binary read-write and truncate the file
fails:File.open raises a TypeError if passed a filename that is not a String or Integer type
fails:File.open raises a SystemCallError if passed an invalid Integer type
fails:File.open raises an ArgumentError if passed an invalid string for mode
fails:File.open defaults external_encoding to ASCII-8BIT for binary modes
79 changes: 0 additions & 79 deletions truffle/src/main/java/org/jruby/truffle/nodes/core/DirNodes.java
Original file line number Diff line number Diff line change
@@ -113,85 +113,6 @@ public boolean exists(RubyString path) {

}

@CoreMethod(names = {"glob", "[]"}, onSingleton = true, required = 1)
public abstract static class GlobNode extends CoreMethodNode {

public GlobNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public GlobNode(GlobNode prev) {
super(prev);
}

@Specialization
public RubyArray glob(RubyString glob) {
return glob(getContext(), glob.toString());
}

@TruffleBoundary
private static RubyArray glob(final RubyContext context, String glob) {
/*
* Globbing is quite complicated. We've implemented a subset of the functionality that
* satisfies MSpec, but it will likely break for anyone else.
*/

final RubyArray array = new RubyArray(context.getCoreLibrary().getArrayClass());
String absoluteGlob;

if (!glob.startsWith("/") && !org.jruby.RubyFile.startsWithDriveLetterOnWindows(glob)) {
absoluteGlob = new File(".", glob).getAbsolutePath();
} else {
absoluteGlob = glob;
}

// Get the first star
final int firstStar = absoluteGlob.indexOf('*');

// If there's no star, it behaves similarly to [glob if File.exist?(glob)].compact
if (firstStar == -1) {
if (new File(glob).exists()) {
array.slowPush(context.makeString(glob));
}
return array;
}

// Walk back from that to the first / before that star

int prefixLength = firstStar;

while (prefixLength > 0 && absoluteGlob.charAt(prefixLength) == File.separatorChar) {
System.out.println(String.format("char: %s; separator: %s", absoluteGlob.charAt(prefixLength), File.separatorChar));
prefixLength--;
}

final String prefix = absoluteGlob.substring(0, prefixLength - 1);

// Glob patterns must always use '/', even on Windows.
final PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:" + absoluteGlob.substring(prefixLength).replace('\\', '/'));

try {
Files.walkFileTree(FileSystems.getDefault().getPath(prefix), new SimpleFileVisitor<Path>() {

@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if (matcher.matches(file)) {
array.slowPush(context.makeString(RubyFile.expandPath(context, file.toString())));
}

return FileVisitResult.CONTINUE;
}

});
} catch (IOException e) {
throw new RuntimeException(e);
}

return array;
}

}

@CoreMethod(names = "mkdir", needsSelf = false, onSingleton = true, required = 1)
public abstract static class MkdirNode extends CoreMethodNode {

Original file line number Diff line number Diff line change
@@ -190,6 +190,18 @@ public Object isCompatible(RubySymbol first, RubySymbol second) {
}
}

@TruffleBoundary
@Specialization
public Object isCompatible(RubyString first, RubyEncoding second) {
final Encoding compatibleEncoding = org.jruby.RubyEncoding.areCompatible(first.getByteList().getEncoding(), second.getEncoding());

if (compatibleEncoding != null) {
return RubyEncoding.getEncoding(compatibleEncoding);
} else {
return nil();
}
}

}

@RubiniusOnly
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/*
* Copyright (c) 2015 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.rubinius;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.UnexpectedResultException;
import com.oracle.truffle.api.object.HiddenKey;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.nodes.objectstorage.ReadHeadObjectFieldNode;
import org.jruby.truffle.nodes.objectstorage.WriteHeadObjectFieldNode;
import org.jruby.truffle.runtime.RubyCallStack;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.*;

import java.io.File;

public abstract class DirPrimitiveNodes {

// TODO CS 14-April-15 use a shape, properties and allocator

private static final HiddenKey contentsKey = new HiddenKey("contents");
private static final HiddenKey positionKey = new HiddenKey("position");

@RubiniusPrimitive(name = "dir_open")
public static abstract class DirOpenPrimitiveNode extends RubiniusPrimitiveNode {

@Child private WriteHeadObjectFieldNode writeContentsNode;
@Child private WriteHeadObjectFieldNode writePositionNode;

public DirOpenPrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
writeContentsNode = new WriteHeadObjectFieldNode(contentsKey);
writePositionNode = new WriteHeadObjectFieldNode(positionKey);
}

public DirOpenPrimitiveNode(DirOpenPrimitiveNode prev) {
super(prev);
writeContentsNode = prev.writeContentsNode;
writePositionNode = prev.writePositionNode;
}

@CompilerDirectives.TruffleBoundary
@Specialization
public RubyNilClass open(RubyBasicObject dir, RubyString path, RubyNilClass encoding) {
final String[] contents = new File(path.toString()).list();

if (contents == null) {
throw new RaiseException(new RubyException(
getContext().getCoreLibrary().getEnoentClass(),
getContext().makeString("No such file or directory @ dir_initialize - " + path.toString()),
RubyCallStack.getBacktrace(this)));
}

writeContentsNode.execute(dir, contents);
writePositionNode.execute(dir, -2); // -2 for . and then ..

return nil();
}

}

@RubiniusPrimitive(name = "dir_read")
public static abstract class DirReadPrimitiveNode extends RubiniusPrimitiveNode {

@Child private ReadHeadObjectFieldNode readContentsNode;
@Child private ReadHeadObjectFieldNode readPositionNode;
@Child private WriteHeadObjectFieldNode writePositionNode;

public DirReadPrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
readContentsNode = new ReadHeadObjectFieldNode(contentsKey);
readPositionNode = new ReadHeadObjectFieldNode(positionKey);
writePositionNode = new WriteHeadObjectFieldNode(positionKey);
}

public DirReadPrimitiveNode(DirReadPrimitiveNode prev) {
super(prev);
readContentsNode = prev.readContentsNode;
readPositionNode = prev.readPositionNode;
writePositionNode = prev.writePositionNode;
}

@CompilerDirectives.TruffleBoundary
@Specialization
public Object read(RubyBasicObject dir) {
final int position;

try {
position = readPositionNode.executeInteger(dir);
} catch (UnexpectedResultException e) {
throw new IllegalStateException();
}

writePositionNode.execute(dir, position + 1);

if (position == -2) {
return getContext().makeString(".");
} else if (position == -1) {
return getContext().makeString("..");
} else {
final String[] contents = (String[]) readContentsNode.execute(dir);

if (position < contents.length) {
return getContext().makeString(contents[position]);
} else {
return nil();
}
}
}

}

@RubiniusPrimitive(name = "dir_close")
public static abstract class DirClosePrimitiveNode extends RubiniusPrimitiveNode {

public DirClosePrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public DirClosePrimitiveNode(DirClosePrimitiveNode prev) {
super(prev);
}

@CompilerDirectives.TruffleBoundary
@Specialization
public RubyNilClass open(RubyBasicObject dir) {
return nil();
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2015 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.rubinius;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubyString;
import org.jruby.util.Dir;

public abstract class IOPrimitiveNodes {

@RubiniusPrimitive(name = "io_fnmatch", needsSelf = false)
public static abstract class IOFNMatchPrimitiveNode extends RubiniusPrimitiveNode {

public IOFNMatchPrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public IOFNMatchPrimitiveNode(IOFNMatchPrimitiveNode prev) {
super(prev);
}

@CompilerDirectives.TruffleBoundary
@Specialization
public boolean fnmatch(RubyString pattern, RubyString path, int flags) {
return Dir.fnmatch(pattern.getByteList().getUnsafeBytes(),
pattern.getByteList().getBegin(),
pattern.getByteList().getBegin() + pattern.getByteList().getRealSize(),
path.getByteList().getUnsafeBytes(),
path.getByteList().getBegin(),
path.getByteList().getBegin() + path.getByteList().getRealSize(),
flags) != Dir.FNM_NOMATCH;
}

}

}
Original file line number Diff line number Diff line change
@@ -59,6 +59,8 @@ public static RubiniusPrimitiveManager create() {
nodeFactories.addAll(StatPrimitiveNodesFactory.getFactories());
nodeFactories.addAll(PointerPrimitiveNodesFactory.getFactories());
nodeFactories.addAll(NativeFunctionPrimitiveNodesFactory.getFactories());
nodeFactories.addAll(DirPrimitiveNodesFactory.getFactories());
nodeFactories.addAll(IOPrimitiveNodesFactory.getFactories());
nodeFactories.addAll(UndefinedPrimitiveNodesFactory.getFactories());

final Map<String, RubiniusPrimitiveConstructor> primitives = new HashMap<>();
Original file line number Diff line number Diff line change
@@ -57,6 +57,40 @@ public Object stat(RubyBasicObject rubyStat, Object path) {

}

@RubiniusPrimitive(name = "stat_lstat")
public static abstract class StatLStatPrimitiveNode extends RubiniusPrimitiveNode {

@Child private WriteHeadObjectFieldNode writeStatNode;

public StatLStatPrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
writeStatNode = new WriteHeadObjectFieldNode(STAT_IDENTIFIER);
}

public StatLStatPrimitiveNode(StatLStatPrimitiveNode prev) {
super(prev);
writeStatNode = prev.writeStatNode;
}

@Specialization
public int lstat(RubyBasicObject rubyStat, RubyString path) {
final FileStat stat = getContext().getRuntime().getPosix().allocateStat();
final int code = getContext().getRuntime().getPosix().lstat(path.toString(), stat);

if (code == 0) {
writeStatNode.execute(rubyStat, stat);
}

return code;
}

@Specialization(guards = "!isRubyString(arguments[1])")
public Object stat(RubyBasicObject rubyStat, Object path) {
return null;
}

}

public static abstract class StatReadPrimitiveNode extends RubiniusPrimitiveNode {

@Child private ReadHeadObjectFieldNode readStatNode;
Original file line number Diff line number Diff line change
@@ -1282,4 +1282,8 @@ public boolean isLoadingRubyCore() {
public boolean isLoaded() {
return state == State.LOADED;
}

public RubyClass getEnoentClass() {
return enoentClass;
}
}
10 changes: 5 additions & 5 deletions truffle/src/main/ruby/core.rb
Original file line number Diff line number Diff line change
@@ -46,14 +46,14 @@
#require_relative 'core/rubinius/bootstrap/constant_cache'
#require_relative 'core/rubinius/bootstrap/constant_scope'
#require_relative 'core/rubinius/bootstrap/constant_table'
#require_relative 'core/rubinius/bootstrap/dir'
require_relative 'core/rubinius/bootstrap/dir'
#require_relative 'core/rubinius/bootstrap/encoding'
#require_relative 'core/rubinius/bootstrap/exception'
#require_relative 'core/rubinius/bootstrap/executable'
require_relative 'core/rubinius/bootstrap/false'
#require_relative 'core/rubinius/bootstrap/fixnum'
require_relative 'core/rubinius/bootstrap/gc'
#require_relative 'core/rubinius/bootstrap/io'
require_relative 'core/rubinius/bootstrap/io'
#require_relative 'core/rubinius/bootstrap/iseq'
#require_relative 'core/rubinius/bootstrap/jit'
require_relative 'core/rubinius/bootstrap/kernel'
@@ -120,7 +120,7 @@
#require_relative 'core/rubinius/common/continuation'
#require_relative 'core/rubinius/common/delegated_method'
require_relative 'core/rubinius/common/fixnum'
#require_relative 'core/rubinius/common/lru_cache'
require_relative 'core/rubinius/common/lru_cache'
require_relative 'core/rubinius/api/shims/encoding'
require_relative 'core/rubinius/common/encoding'
#require_relative 'core/rubinius/common/env'
@@ -130,8 +130,8 @@
#require_relative 'core/rubinius/common/fiber'
#require_relative 'core/rubinius/common/io'
require_relative 'core/rubinius/common/file'
#require_relative 'core/rubinius/common/dir'
#require_relative 'core/rubinius/common/dir_glob'
require_relative 'core/rubinius/common/dir'
require_relative 'core/rubinius/common/dir_glob'
#require_relative 'core/rubinius/common/file_test'
require_relative 'core/rubinius/common/stat'
require_relative 'core/rubinius/common/float'
78 changes: 78 additions & 0 deletions truffle/src/main/ruby/core/rubinius/bootstrap/dir.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Copyright (c) 2007-2014, Evan Phoenix and contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Rubinius nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

class Dir
def self.allocate
Rubinius.primitive :dir_allocate
raise PrimitiveFailure, "Dir.allocate primitive failed"
end

def initialize(path, options=undefined)
path = Rubinius::Type.coerce_to_path path

if options.equal? undefined
enc = nil
else
options = Rubinius::Type.coerce_to options, Hash, :to_hash
enc = options[:encoding]
enc = Rubinius::Type.coerce_to_encoding enc if enc
end

Rubinius.invoke_primitive :dir_open, self, path, enc
end

private :initialize

def close
Rubinius.primitive :dir_close
raise PrimitiveFailure, "Dir#close primitive failed"
end

def closed?
Rubinius.primitive :dir_closed_p
raise PrimitiveFailure, "Dir#closed? primitive failed"
end

def read
entry = Rubinius.invoke_primitive :dir_read, self
return unless entry

if Encoding.default_external == Encoding::US_ASCII && !entry.valid_encoding?
entry.force_encoding Encoding::ASCII_8BIT
return entry
end

enc = Encoding.default_internal
enc ? entry.encode(enc) : entry
end

def control(kind, pos)
Rubinius.primitive :dir_control
raise PrimitiveFailure, "Dir#__control__ primitive failed"
end

private :control
end
36 changes: 36 additions & 0 deletions truffle/src/main/ruby/core/rubinius/bootstrap/io.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Copyright (c) 2007-2014, Evan Phoenix and contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Rubinius nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

# Only part of Rubinius' io.rb

class IO

def self.fnmatch(pattern, path, flags)
Rubinius.primitive :io_fnmatch
raise PrimitiveFailure, "IO#fnmatch primitive failed"
end

end
85 changes: 85 additions & 0 deletions truffle/src/main/ruby/core/rubinius/common/dir.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Copyright (c) 2007-2014, Evan Phoenix and contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Rubinius nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

# Only part of Rubinius' dir.rb

class Dir

def self.[](*patterns)
if patterns.size == 1
pattern = Rubinius::Type.coerce_to_path(patterns[0])
return [] if pattern.empty?
patterns = glob_split pattern
end

glob patterns
end

def self.glob(pattern, flags=0, &block)
if pattern.kind_of? Array
patterns = pattern
else
pattern = Rubinius::Type.coerce_to_path pattern

return [] if pattern.empty?

patterns = glob_split pattern
end

matches = []
index = 0

patterns.each do |pat|
pat = Rubinius::Type.coerce_to_path pat
enc = Rubinius::Type.ascii_compatible_encoding pat
Dir::Glob.glob pat, flags, matches

total = matches.size
while index < total
Rubinius::Type.encode_string matches[index], enc
index += 1
end
end

if block
matches.each(&block)
return nil
end

return matches
end

def self.glob_split(pattern)
result = []
start = 0
while idx = pattern.find_string("\0", start)
result << pattern.byteslice(start, idx)
start = idx + 1
end
result << pattern.byteslice(start, pattern.bytesize)
end

end
489 changes: 489 additions & 0 deletions truffle/src/main/ruby/core/rubinius/common/dir_glob.rb

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion truffle/src/main/ruby/core/rubinius/common/exception.rb
Original file line number Diff line number Diff line change
@@ -26,7 +26,6 @@

# Only part of Rubinius' exception.rb


class NoMethodError < NameError
attr_reader :name
attr_reader :args
157 changes: 157 additions & 0 deletions truffle/src/main/ruby/core/rubinius/common/file.rb
Original file line number Diff line number Diff line change
@@ -29,6 +29,14 @@
class File < IO
include Enumerable

module Constants
FNM_NOESCAPE = 0x01
FNM_PATHNAME = 0x02
FNM_DOTMATCH = 0x04
FNM_CASEFOLD = 0x08
FNM_EXTGLOB = 0x10
end

FFI = Rubinius::FFI

POSIX = FFI::Platform::POSIX
@@ -113,6 +121,7 @@ def self.unlink(*paths)
class << self
alias_method :delete, :unlink
alias_method :exists?, :exist?
alias_method :fnmatch?, :fnmatch
end

def self.path(obj)
@@ -186,6 +195,154 @@ def self.basename(path, ext=undefined)
return path
end

def self.braces(pattern, flags=0, patterns=[])
escape = (flags & FNM_NOESCAPE) == 0

rbrace = nil
lbrace = nil

# Do a quick search for a { to start the search better
i = pattern.index("{")

if i
nest = 0

while i < pattern.size
char = pattern[i]

if char == "{"
lbrace = i if nest == 0
nest += 1
end

if char == "}"
nest -= 1
end

if nest == 0
rbrace = i
break
end

if char == "\\" and escape
i += 1
end

i += 1
end
end

# There was a full {} expression detected, expand each part of it
# recursively.
if lbrace and rbrace
pos = lbrace
front = pattern[0...lbrace]
back = pattern[(rbrace + 1)..-1]

while pos < rbrace
nest = 0
pos += 1
last = pos

while pos < rbrace and not (pattern[pos] == "," and nest == 0)
nest += 1 if pattern[pos] == "{"
nest -= 1 if pattern[pos] == "}"

if pattern[pos] == "\\" and escape
pos += 1
break if pos == rbrace
end

pos += 1
end

brace_pattern = "#{front}#{pattern[last...pos]}#{back}"
patterns << brace_pattern

braces(brace_pattern, flags, patterns)
end
end
patterns
end

##
# Returns true if path matches against pattern The pattern
# is not a regular expression; instead it follows rules
# similar to shell filename globbing. It may contain the
# following metacharacters:
#
# *: Matches any file. Can be restricted by other values in the glob. * will match all files; c* will match all files beginning with c; *c will match all files ending with c; and c will match all files that have c in them (including at the beginning or end). Equivalent to / .* /x in regexp.
# **: Matches directories recursively or files expansively.
# ?: Matches any one character. Equivalent to /.{1}/ in regexp.
# [set]: Matches any one character in set. Behaves exactly like character sets in Regexp, including set negation ([^a-z]).
# <code></code>: Escapes the next metacharacter.
# flags is a bitwise OR of the FNM_xxx parameters. The same glob pattern and flags are used by Dir::glob.
#
# File.fnmatch('cat', 'cat') #=> true : match entire string
# File.fnmatch('cat', 'category') #=> false : only match partial string
# File.fnmatch('c{at,ub}s', 'cats') #=> false : { } isn't supported
# File.fnmatch('c{at,ub}s', 'cats', File::FNM_EXTGLOB) #=> true : { } is supported with FNM_EXTGLOB
#
# File.fnmatch('c?t', 'cat') #=> true : '?' match only 1 character
# File.fnmatch('c??t', 'cat') #=> false : ditto
# File.fnmatch('c*', 'cats') #=> true : '*' match 0 or more characters
# File.fnmatch('c*t', 'c/a/b/t') #=> true : ditto
# File.fnmatch('ca[a-z]', 'cat') #=> true : inclusive bracket expression
# File.fnmatch('ca[^t]', 'cat') #=> false : exclusive bracket expression ('^' or '!')
#
# File.fnmatch('cat', 'CAT') #=> false : case sensitive
# File.fnmatch('cat', 'CAT', File::FNM_CASEFOLD) #=> true : case insensitive
#
# File.fnmatch('?', '/', File::FNM_PATHNAME) #=> false : wildcard doesn't match '/' on FNM_PATHNAME
# File.fnmatch('*', '/', File::FNM_PATHNAME) #=> false : ditto
# File.fnmatch('[/]', '/', File::FNM_PATHNAME) #=> false : ditto
#
# File.fnmatch('\?', '?') #=> true : escaped wildcard becomes ordinary
# File.fnmatch('\a', 'a') #=> true : escaped ordinary remains ordinary
# File.fnmatch('\a', '\a', File::FNM_NOESCAPE) #=> true : FNM_NOESACPE makes '\' ordinary
# File.fnmatch('[\?]', '?') #=> true : can escape inside bracket expression
#
# File.fnmatch('*', '.profile') #=> false : wildcard doesn't match leading
# File.fnmatch('*', '.profile', File::FNM_DOTMATCH) #=> true period by default.
# File.fnmatch('.*', '.profile') #=> true
#
# rbfiles = '**' '/' '*.rb' # you don't have to do like this. just write in single string.
# File.fnmatch(rbfiles, 'main.rb') #=> false
# File.fnmatch(rbfiles, './main.rb') #=> false
# File.fnmatch(rbfiles, 'lib/song.rb') #=> true
# File.fnmatch('**.rb', 'main.rb') #=> true
# File.fnmatch('**.rb', './main.rb') #=> false
# File.fnmatch('**.rb', 'lib/song.rb') #=> true
# File.fnmatch('*', 'dave/.profile') #=> true
#
# pattern = '*' '/' '*'
# File.fnmatch(pattern, 'dave/.profile', File::FNM_PATHNAME) #=> false
# File.fnmatch(pattern, 'dave/.profile', File::FNM_PATHNAME | File::FNM_DOTMATCH) #=> true
#
# pattern = '**' '/' 'foo'
# File.fnmatch(pattern, 'a/b/c/foo', File::FNM_PATHNAME) #=> true
# File.fnmatch(pattern, '/a/b/c/foo', File::FNM_PATHNAME) #=> true
# File.fnmatch(pattern, 'c:/a/b/c/foo', File::FNM_PATHNAME) #=> true
# File.fnmatch(pattern, 'a/.b/c/foo', File::FNM_PATHNAME) #=> false
# File.fnmatch(pattern, 'a/.b/c/foo', File::FNM_PATHNAME | File::FNM_DOTMATCH) #=> true

def self.fnmatch(pattern, path, flags=0)
pattern = StringValue(pattern)
path = Rubinius::Type.coerce_to_path(path)
flags = Rubinius::Type.coerce_to(flags, Fixnum, :to_int)
brace_match = false

if (flags & FNM_EXTGLOB) != 0
brace_match = braces(pattern, flags).any? { |p| super(p, path, flags) }
end
brace_match || super(pattern, path, flags)
end

end

File::Stat = Rubinius::Stat

# Inject the constants into IO
class IO
include File::Constants
end
169 changes: 169 additions & 0 deletions truffle/src/main/ruby/core/rubinius/common/lru_cache.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
# Copyright (c) 2007-2014, Evan Phoenix and contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Rubinius nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

module Rubinius
class LRUCache
class Entry
attr_reader :hits
attr_reader :key
attr_accessor :value
attr_accessor :next_entry
attr_accessor :prev_entry

def initialize(key, value)
@key = key
@value = value
@hits = 0
@next_entry = nil
@prev_entry = nil
end

def insert_after(entry)
nxt = entry.next_entry

@prev_entry = entry
@next_entry = nxt

entry.next_entry = self
nxt.prev_entry = self if nxt
end

def insert_before(entry)
prev = entry.prev_entry

@prev_entry = prev
@next_entry = entry

entry.prev_entry = self
prev.next_entry = self if prev
end

def detach!
@next_entry.prev_entry = @prev_entry if @next_entry
@prev_entry.next_entry = @next_entry if @prev_entry

@next_entry = nil
@prev_entry = nil
end

def become_first!
@prev_entry = nil
end

def inc!
@hits += 1
end
end

def initialize(total)
@cache = {}
@total = total
@current = 0

@head = Entry.new(nil, nil)
@tail = Entry.new(nil, nil)

@tail.insert_after(@head)

@misses = 0
end

attr_reader :current
attr_reader :misses

def clear!
Rubinius.synchronize(self) do
@cache = {}
@current = 0

@head = Entry.new(nil, nil, -1)
@tail = Entry.new(nil, nil, -2)

@tail.insert_after(@head)
end
end

def explain
entry = @head.next_entry
while entry != @tail
str, layout = entry.key
puts "hits: #{entry.hits}"
puts "layout: #{layout.inspect}"
puts "<STRING>"
puts str
puts "</STRING>"

entry = entry.next_entry
end
end

def retrieve(key)
Rubinius.synchronize(self) do
if entry = @cache[key]
entry.inc!

entry.detach!
entry.insert_before @tail

return entry.value
end

@misses += 1

nil
end
end

def set(key, value)
Rubinius.synchronize(self) do
if entry = @cache[key]
entry.value = value

entry.detach!
entry.insert_before @tail

return value
end

if @current == @total
entry = @head.next_entry

entry.detach!

@cache.delete entry.key
else
@current += 1
end

entry = Entry.new(key, value)

entry.insert_before @tail

@cache[key] = entry
end
end
end
end
10 changes: 10 additions & 0 deletions truffle/src/main/ruby/core/shims.rb
Original file line number Diff line number Diff line change
@@ -215,3 +215,13 @@ class Rubinius::ByteArray

end

# Don't apply any synchronization at the moment

module Rubinius

def self.synchronize(object)
yield
end

end

0 comments on commit 3063622

Please sign in to comment.