Git Product home page Git Product logo

artichoke's Introduction

Artichoke Ruby

GitHub Actions Discord Twitter
Crate API API trunk

Artichoke Ruby logo

Artichoke is a Ruby implementation written in Rust and Ruby. Artichoke intends to be MRI-compatible and targets recent MRI Ruby. Artichoke provides a Ruby runtime implemented in Rust and Ruby.

Try Artichoke

Artichoke Ruby WebAssembly playground
Artichoke Ruby Wasm Playground

You can try Artichoke in your browser. The Artichoke Playground runs a WebAssembly build of Artichoke.

Install Artichoke

Prebuilt nightly binaries

Download a prebuilt binary from artichoke/nightly. Binaries are available for Linux, Linux/musl, macOS, and Windows.

These daily binaries track the latest trunk branch of Artichoke.

Binaries are also distributed through ruby-build. To install with rbenv:

$ rbenv install artichoke-dev

Cargo

You can install a pre-release build of Artichoke using cargo, Rust's package manager, by running:

$ cargo install --git https://github.com/artichoke/artichoke --branch trunk --locked artichoke

To install via cargo install or to checkout and build locally, you'll need Rust and clang. BUILD.md has more detail on how to set up the compiler toolchain.

Docker

Artichoke is available on Docker Hub.

You can launch a REPL by running:

docker run -it docker.io/artichokeruby/artichoke airb

Usage

Artichoke ships with two binaries: airb and artichoke.

airb

airb is the Artichoke implementation of irb and is an interactive Ruby shell and REPL.

airb is a readline-enabled shell, although it does not persist history.

artichoke

artichoke is the ruby binary frontend to Artichoke.

artichoke supports executing programs via files, stdin, or inline with one or more -e flags.

Artichoke can require, require_relative, and load files from the local file system, but otherwise does not yet support local file system access. A temporary workaround is to inject data into the interpreter with the --with-fixture flag, which reads file contents into a $fixture global.

$ artichoke --help
Artichoke is a Ruby made with Rust.

Usage: artichoke [OPTIONS] [programfile] [arguments]...

Arguments:
  [programfile]
  [arguments]...

Options:
      --copyright               print the copyright
  -e <commands>                 one line of script. Several -e's allowed. Omit [programfile]
      --with-fixture <fixture>  file whose contents will be read into the `$fixture` global
  -h, --help                    Print help
  -V, --version                 Print version

Design and Goals

Artichoke is designed to enable experimentation. The top goals of the project are:

Contributing

Artichoke aspires to be an MRI Ruby-compatible implementation of the Ruby programming language. There is lots to do.

If Artichoke does not run Ruby source code in the same way that MRI does, it is a bug and we would appreciate if you filed an issue so we can fix it.

If you would like to contribute code ๐Ÿ‘ฉโ€๐Ÿ’ป๐Ÿ‘จโ€๐Ÿ’ป, find an issue that looks interesting and leave a comment that you're beginning to investigate. If there is no issue, please file one before beginning to work on a PR. Good first issues are labeled E-easy.

Discussion

If you'd like to engage in a discussion outside of GitHub, you can join Artichoke's public Discord server.

License

artichoke is licensed with the MIT License (c) Ryan Lopopolo.

Some portions of Artichoke are derived from third party sources. The READMEs in each workspace crate discuss which third party licenses are applicable to the sources and derived works in Artichoke.

artichoke's People

Contributors

afaur avatar artichoke-ci avatar b-n avatar cdeler avatar choznerol avatar dependabot-preview[bot] avatar dependabot[bot] avatar druzn3k avatar ekroon avatar felipecsl avatar iwillspeak avatar johnwahba avatar jonkgrimes avatar kbuild avatar kijewski avatar kolharsam avatar lopopolo avatar masonforest avatar michaeltaras avatar mmizutani avatar nlightnfotis avatar silathdiir avatar stuarth avatar sudopluto avatar tanaythan avatar thommahoney avatar tkbky avatar tseyang avatar xulaus avatar zaccari avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

artichoke's Issues

Implement the Ruby 2.6 standard library tracking ticket

Implement the Ruby 2.6.3 Standard Library.

This ticket tracks the scheduling and completion of the [Standard Library Milestone]. Checkmarks mean a ticket to track package implementation has been created.

Implement Convert<HashMap<Value, Value>>

Once #28 lands, Value is a valid key for a HashMap.

Implementing Convert<HashMap<Value, Value>> allows us to follow the same approach as Array and massively simplify the macro madness in hash.rs.

I think this should also unify the special-cased &str converters.

Move path canonicalization into fs module

Right now path canonicalization and absolutifying lives in the implementation of Kernel#require. This means that I think this code behaves unexpectedly:

interp.def_rb_source_file("../spec_helper.rb", "")

Move path canonicalization into the fs layer.

Make MrbError::Exec wrap an Exception

Right now, MrbError::Exec wraps a stringified stack trace.

The MrbExceptionHandler exposes a nice Exception struct that exposes exception class, message, optional backtrace, and the result of exc.inspect. It also implements display.

Wrap this Exception struct instead.

Implement $LOAD_PATH

Currently, the load path for require is hardcoded as /src/lib. This value should be exposed via the $LOAD_PATH global and Kernel#require should respect this configuration.

  • $LOAD_PATH global
  • read $LOAD_PATH in require Rust implementation
  • support trying multiple load locations

NOTE: mruby does not support aliasing globals so we should punt on implementing the $: shorthand alias (even though we could with shared Rust state and the proposed global registry, see artichoke/ferrocarril#14).

Remove dependency on mruby-*-ext mrbgems

These implementations of Ruby core methods have been mostly buggy and not spec-compliant.

Use them as a starting point to implement them natively in Rust/evaled Ruby with the goal of passing ruby/spec.

  • mruby-compar-ext
  • mruby-enum-ext
  • mruby-numeric-ext
  • mruby-array-ext
  • mruby-hash-ext
  • mruby-range-ext
  • mruby-proc-ext
  • mruby-symbol-ext
  • mruby-object-ext
  • mruby-kernel-ext
  • mruby-class-ext

Split global (singleton) functions out of method.rs

Global functions are always implemented on top_self so they do not take a parent sys::RClass *. We also likely want to keep a separate registry for them to make them easier to create.

Once we implement support for proc-macros (see #38), these functions will have a separate creation pathway, too.

Fix behavior of String#ord when String contains invalid UTF-8 byte sequence

CRuby:

[2.6.3] > "\xFE".ord
Traceback (most recent call last):
        5: from /usr/local/var/rbenv/versions/2.6.3/bin/irb:23:in `<main>'
        4: from /usr/local/var/rbenv/versions/2.6.3/bin/irb:23:in `load'
        3: from /usr/local/var/rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>'
        2: from (irb):2
        1: from (irb):2:in `ord'
ArgumentError (invalid byte sequence in UTF-8)

rirb:

>>> "\xFE".ord
=> nil

Turn MRB_TT_EXCEPTION Values into MrbError::Exec

If an exception is thrown in the context of a C API call, the returned mrb_value is of type mrb_vtype::MRB_TT_EXCEPTION. Turn this exception into an Err(MrbError::Exec(_)).

Maybe as part of a funcall interface on Value?

Artichoke tracking ticket

The focus of this repository is changing and the scope is growing. We are building a Ruby ๐Ÿ’Ž!

Artichoke aims to be a source-compatible, ruby/spec compliant implementation of Ruby 2.6.3 written in safe Rust (excluding crate dependencies).

Go get there, we'll use the mruby base and continue to rip parts of it out of libmruby.a into the mruby crate with the goal of passing as many of the core specs as possible only by removing dependencies on mrbgems.

Complete the implementation of Ruby stdlib.

Implement File and IO in Ruby core.

Once the mrbgem dependencies are minimized, start reimplmenting the mruby C API in Rust one header at a time. There are 311 C functions.

Then we'll be left with the compiler, parser, GC, mrb_state, and VM. Figure out a way to migrate these into Rust.

Build a ruby CLI frontend.

Build support for concurrent Threads.

Remove RefCell from Class and Module specs

Just make Define mutable and store the RClass. In ClassLike::rclass, short circuit if rclass is Some and resolve the RClass using the mruby C API. Don't store this result to keep the API simple and not require mutability.

Implement File

Implement the File class in Rust so that it is backed by the vfs on the State.

Add tests for regexp::opts::parse_pattern

There is a gnarly state machine and String processing going on. Needs tests, which should help as we modify this function to be backed by a nom parser.

// TODO: Add tests for this parse_pattern, see GH-157.
pub fn parse_pattern(pattern: &str, mut opts: Options) -> (String, Options) {
let orig_opts = opts;
let mut chars = pattern.chars();
let mut enabled = true;
let mut pat_buf = String::new();
let mut pointer = 0;
match chars.next() {
None => {
pat_buf.push_str("(?");
pat_buf.push_str(opts.onig_string().as_str());
pat_buf.push(':');
pat_buf.push(')');
return (pat_buf, opts);
}
Some(token) if token != '(' => {
pat_buf.push_str("(?");
pat_buf.push_str(opts.onig_string().as_str());
pat_buf.push(':');
pat_buf.push_str(pattern);
pat_buf.push(')');
return (pat_buf, opts);
}
_ => (),
};
pointer += 1;
match chars.next() {
None => {
pat_buf.push_str("(?");
pat_buf.push_str(opts.onig_string().as_str());
pat_buf.push(':');
pat_buf.push_str(pattern);
pat_buf.push(')');
return (pat_buf, opts);
}
Some(token) if token != '?' => {
pat_buf.push_str("(?");
pat_buf.push_str(opts.onig_string().as_str());
pat_buf.push(':');
pat_buf.push_str(pattern);
pat_buf.push(')');
return (pat_buf, opts);
}
_ => (),
};
pointer += 1;
for token in chars {
pointer += 1;
match token {
'-' => enabled = false,
'i' => {
opts.ignore_case = enabled;
}
'm' => {
opts.multiline = enabled;
}
'x' => {
opts.extended = enabled;
}
':' => break,
_ => {
pat_buf.push_str("(?");
pat_buf.push_str(opts.onig_string().as_str());
pat_buf.push(':');
pat_buf.push_str(pattern);
pat_buf.push(')');
return (pat_buf, opts);
}
}
}
let mut chars = pattern[pointer..].chars();
let mut token = chars.next();
let mut nest = 1;
while token.is_some() {
match token {
Some(token) if token == '(' => nest += 1,
Some(token) if token == ')' => {
nest -= 1;
if nest == 0 && chars.next().is_some() {
return (
format!("(?{}:{})", orig_opts.onig_string(), pattern),
orig_opts,
);
}
break;
}
_ => (),
}
token = chars.next();
}
(
format!("(?{}:{}", opts.onig_string(), &pattern[pointer..]),
opts,
)
}

Implement Object#object_id

This is the algorithm for Fixnum:

[2.6.0] > 122732743347.object_id
=> 245465486695
[2.6.0] > ((122732743347 << 1) | 0x1)
=> 245465486695
[2.6.0] > -122732743347.object_id
=> -245465486693
[2.6.0] > (0x1 << 1) - ((122732743347 << 1) | 0x1)
=> -245465486693

Don't mutably borrow in Define::define

This code looks like it should work but it panics:

let metrics = interp
            .borrow()
            .module_spec::<Metrics>();
            .and_then(|spec| spec.borrow().value(&interp));

See if there is a way to fix this. Maybe by interning the symbol when we have the mutable borrow in def_module and passing it to module::Spec?

see also #21.

Add support for the wasm32-unknown-unknown build target

Support the wasm32-unknown-unknown target, which would enable using a native web Wasm runtime and unlock the ability to use wasm-bindgen, stdweb, and lots of other goodies in the playground.

With our fork of rust-onig, the only thing remaining to support this is getting mruby building under wasm32-unknown-unknown.

Implement PartialEq, Eq, and Hash on Value

Now that each Value has an interpreter associated with it (did not used to be the case), we can implement Hash with funcall("hash") and PartialEq with funcall("==", &[other])

This will enable storing Value in a HashMap, see artichoke/ferrocarril#160.

Revendor mruby and re-enable thread test when upstream bug is fixed

The vendored version of mruby has a bug where in some situations comments do not increment the line number in the parser. This breaks tests which test stack traces. thread.rs has one of these tests that has been disabled. Pull in the upstream bugfix and re-enable the test.

Upstream bug: mruby/mruby#4513

Disabled test:

https://github.com/lopopolo/ferrocarril/blob/329c544006b619b7b4fac9c96b6b5ec51a311a84/mruby/src/extn/core/thread.rs#L155-L194

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.