Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ fn main() {
let mut builder = bindgen::Builder::default()
.header("./vendor/mruby-compiler2/include/mruby_compiler.h")
.header("./vendor/mruby-compiler2/include/mrc_codedump.h")
.clang_arg("-DMRB_NO_PRESYM")
.clang_arg("-DMRB_INT64=1")
.clang_arg("-DPRISM_XALLOCATOR")
.clang_arg("-DPRISM_BUILD_MINIMAL")
.clang_arg("-DPICORB_VM_MRUBYC")
.clang_arg("-DMRBC_ALLOC_LIBC")
.clang_arg("-I./vendor/include")
.clang_arg("-I./vendor/mruby-compiler2/include")
.clang_arg("-I./vendor/mruby-compiler2/lib/prism/include")
.blocklist_item("FP_NAN")
Expand Down
2 changes: 1 addition & 1 deletion vendor/mruby-compiler2/LICENSE
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
mruby-compiler2
mruby-compiler-prism / mruby-compiler2

Copyright (c) HASUMI Hitoshi 2024

Expand Down
135 changes: 126 additions & 9 deletions vendor/mruby-compiler2/README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,137 @@
# mruby-compiler2
# mruby-compiler / mruby-compiler2

New mruby compiler based on Prism.
This project is a Prism-based Ruby parser and bytecode compiler for mruby, PicoRuby, and FemtoRuby.

## install by mrbgems
Read this note first:

- add conf.gem line to `build_config.rb`
- If this file is under `mruby/mrbgems/mruby-compiler`, you are reading the canonical mruby core mgem. This is where development happens.
- If this file is at the top of `picoruby/mruby-compiler2`, you are reading the standalone mirror. That repository exists for projects that need to use the compiler independently from mruby and pin it at an arbitrary commit.
- Please send patches to `mruby/mruby`, not to `picoruby/mruby-compiler2`. The standalone repository is synchronized from mruby after changes land there.

The compiler must remain usable without fundamentally depending on mruby. mruby uses it as `mruby-compiler`; PicoRuby and FemtoRuby use the same compiler through the standalone `mruby-compiler2` mirror.

## Using mruby-compiler2 as a standalone mgem

Projects that want to pin the compiler independently from mruby can use:

```ruby
MRuby::Build.new do |conf|
conf.gem github: "picoruby/mruby-compiler2", commit: "..."
end
```

# ... (snip) ...
`picoruby/mruby-compiler2` is synchronized from
`mruby/mruby/mrbgems/mruby-compiler`. It may lag behind mruby until the sync workflow opens and merges a mirror PR.

conf.gem :github => 'picoruby/mruby-compiler2'
end
## Using Prism in mruby

Prism support in mruby is opt-in:

```sh
MRB_COMPILER_PRISM=yes rake test
```

The top-level mruby `Rakefile` maps `MRB_COMPILER_PRISM=yes` to `MRUBY_CONFIG=prism` only when neither `MRUBY_CONFIG` nor `CONFIG` is already set. Explicit config selection continues to win:

```sh
MRUBY_CONFIG=ci/gcc-clang rake test
MRUBY_CONFIG=prism rake test
```

This keeps the normal mruby build and CI path compatible with the existing `mruby-compiler` gem while Prism support is still being aligned.

The Prism route currently includes:

- `mruby-compiler`
- `mruby-bin-mrbc`
- `mruby-bin-mruby`
- `mruby-bin-mirb`
- `mruby-eval`

## Prism submodule and bootstrap

`lib/prism` is a git submodule pointing at `ruby/prism`.

The gem bootstrap runs before `mrbgem.rake` collects Prism C sources with `Dir.glob`. This matters for fresh checkouts, where the submodule may not yet be initialized and generated Prism files may be absent.

During normal build setup, `mrbgem.rake` does the following:

1. If `lib/prism/templates/template.rb` is missing, run:

```sh
git submodule update --init lib/prism
```

2. If generated Prism files such as `src/node.c`, `src/serialize.c`, `include/prism/ast.h`, or `include/prism/diagnostic.h` are missing, run:

```sh
ruby templates/template.rb
```

This bootstrap belongs in the compiler gem because the same source tree is used from mruby, PicoRuby, FemtoRuby, and the standalone mirror.

## Compatibility requirements

The compiler is shared by multiple runtimes. Changes made for mruby must preserve these boundaries.

1. Do not introduce a fundamental dependency on mruby.

The compiler should continue to build for both `MRC_TARGET_MRUBY` and `MRC_TARGET_MRUBYC`. mruby-only compatibility code must stay behind `MRC_TARGET_MRUBY`.

2. The compiler library must not define `global_mrb`.

The executable or embedding runtime owns `global_mrb` when the mruby allocator path needs it. This avoids duplicate-symbol conflicts in PicoRuby and r2p2. In standalone mruby, `mrbc-prism`, `mruby-prism`, `mirb-prism`, and `mrbtest` provide the owner when building the Prism route.

3. `PICORB_VM_MRUBY` and `PICORB_VM_MRUBYC` must remain respected.

PicoRuby builds the mruby VM path. FemtoRuby builds the mruby/c VM path. The gem configuration must not accidentally select `MRC_TARGET_MRUBY` while building FemtoRuby.

4. Public compiler headers are the API boundary for PicoRuby and FemtoRuby.

Keep the C API usable without depending on mruby internals:
- `mrc_common.h`
- `mrc_ccontext.h`
- `mrc_compile.h`
- `mrc_dump.h`

5. Do not hard-code the PicoRuby submodule path.

PicoRuby intentionally uses top-level gems such as `mrbgems/mruby-compiler-prism` or the standalone `mruby-compiler2` mirror and synchronizes them at chosen times.

6. `mruby-eval-prism` is for the mruby VM path.

FemtoRuby uses `picoruby-eval`, loaded as a prebuilt gem. On FemtoRuby, `eval` is available after:

```ruby
require "eval"
```

## Current status

`MRB_COMPILER_PRISM=yes rake test:build` currently passes in the local port. The Prism build links:

- `mrbc-prism`
- `mruby-prism`
- `mirb-prism`
- `mrbtest`

Basic execution works:

```sh
build/host/bin/mruby-prism -e 'p 1 + 2'
#=> 3

build/host/bin/mruby-prism -e 'p eval("1 + 2")'
#=> 3
```

Known remaining work:

- `MRB_COMPILER_PRISM=yes rake test:run:lib` reached `mrbtest` locally but failed in the socket tests with an AF_UNIX bind error. This should be rechecked in upstream CI before treating it as a Prism compiler issue.
- `MRB_COMPILER_PRISM=yes rake test:run:bin` still has Prism-specific bintest failures around diagnostics, verbose dump output, top-level locals, and `mirb-prism` multi-line behavior.
- `mruby-bin-strip-prism` does not exist yet.
- Some non-Prism gems and gemboxes still refer directly to `mruby-compiler`.

## License
under the MIT License:
- see LICENSE file

MIT License. See `LICENSE`.
15 changes: 14 additions & 1 deletion vendor/mruby-compiler2/include/mrc_ccontext.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ typedef struct mrc_ccontext {
char *filename;
uint16_t lineno;
struct RClass *target_class;
mrc_bool capture_errors:1;
mrc_bool capture_errors:1; /* output: an error was recorded */
mrc_bool quiet_errors:1; /* input: caller reports them itself (eval) */
mrc_bool dump_ast:1;
mrc_bool dump_result:1;
mrc_bool no_exec:1;
mrc_bool keep_lv:1;
Expand All @@ -59,6 +61,17 @@ typedef struct mrc_ccontext {
uint16_t filename_table_length;
uint16_t current_filename_index;
#endif

/* The arena everything Prism allocates for this context is taken from, and
the arena of the context this one was made inside of, put back when this
one is freed. Unused where Prism allocates through libc; see
prism_xallocator.h for what the arena is for. */
void *prism_arena;
void *prism_arena_outer;

/* How deep the brackets stand where the lexer is, so that a nesting Prism
would recurse through is refused instead. See src/compile.c. */
uint32_t nesting;
} mrc_ccontext; /* compiler context */

#ifdef MRC_TARGET_MRUBY
Expand Down
1 change: 0 additions & 1 deletion vendor/mruby-compiler2/include/mrc_cdump.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,3 @@ MRC_END_DECL
int mrc_dump_irep_cstruct(mrc_ccontext *c, const mrc_irep *irep, uint8_t flags, FILE *fp, const char *initname);

#endif // MRC_CDUMP_H

1 change: 0 additions & 1 deletion vendor/mruby-compiler2/include/mrc_codedump.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,3 @@ void mrc_codedump_all(mrc_ccontext *c, mrc_irep *irep);
MRC_END_DECL

#endif // MRC_CODEDUMP_H

1 change: 0 additions & 1 deletion vendor/mruby-compiler2/include/mrc_codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,3 @@ mrc_irep *mrc_generate_code(mrc_ccontext *c, mrc_node *node);
MRC_END_DECL

#endif // MRC_CODEGEN_H

65 changes: 47 additions & 18 deletions vendor/mruby-compiler2/include/mrc_common.h
Original file line number Diff line number Diff line change
@@ -1,47 +1,69 @@
#ifndef MRC_COMMON_H
#define MRC_COMMON_H

#include <stdint.h>

#define MRC_STRINGIZE0(expr) #expr
#define MRC_STRINGIZE(expr) MRC_STRINGIZE0(expr)

#if defined(PICORB_VM_MRUBY)
#if !defined(MRC_TARGET_MRUBY)
#define MRC_TARGET_MRUBY
#endif
#include <mruby.h>
#endif
#if defined(PICORB_VM_MRUBYC)
#if !defined(MRC_TARGET_MRUBYC)
#define MRC_TARGET_MRUBYC
#endif
#include <mrubyc.h>
#define mrb_state void
#endif

#if !defined(MRC_TARGET_MRUBY) && !defined(PICORB_VM_MRUBYC)
/* May be building mrbc (picorbc) */
/* mruby.h must be included before <stdint.h> (it enforces this ordering on
some platforms) and it carries the core API's linkage, so include it up
front -- and outside the extern "C" wrap below. prism.h pulls mruby.h in
transitively through prism_xallocator.h; keeping it out of the wrap means
that under MRB_USE_CXX_ABI the core keeps its C++ linkage while only Prism
gets C linkage. */
#if defined(MRC_TARGET_MRUBY)
#include <mruby.h>
#elif defined(MRC_TARGET_MRUBYC)
#include <mrubyc.h>
#define mrb_state void
#else
/* May be building standalone mrbc. mruby.h would declare a core API this
binary does not link, but mrbconf.h on its own is self-contained, and it
is what settles the target's mrb_int width -- which mrc_int has to match,
because this mrbc dumps irep for that target (see MRC_INT32 below). */
#include <stdint.h>
#include <mrbconf.h>
#define mrb_state void
#endif

#include <stdint.h>

#if !defined(PRISM_XALLOCATOR)
#define PRISM_XALLOCATOR
#endif
/* Prism is a vendored C library and is always compiled as C (its generated
code uses C constructs -- designated initializers, implicit void* casts --
that a C++ compiler cannot build). When this header is included from a C++
translation unit -- e.g. an MRB_USE_CXX_ABI build -- its declarations must
use C linkage so they match the C-compiled Prism objects. */
#ifdef __cplusplus
extern "C" {
#endif
#include "prism.h"

#ifndef PICORUBY_VERSION
#define MRC_VERSION "unknown (standalone)"
#else
#define MRC_VERSION PICORUBY_VERSION
#ifdef __cplusplus
}
#endif

#define MRC_RELEASE_YEAR 2026
#define MRC_RELEASE_MONTH 1
#define MRC_RELEASE_DAY 21
#define MRC_RELEASE_DATE MRC_STRINGIZE(MRC_RELEASE_YEAR) "-" \
MRC_STRINGIZE(MRC_RELEASE_MONTH) "-" \
MRC_STRINGIZE(MRC_RELEASE_DAY)
#ifndef MRC_COMMIT_TIMESTAMP
#define MRC_COMMIT_TIMESTAMP "unknown"
#endif
#ifndef MRC_COMMIT_BRANCH
#define MRC_COMMIT_BRANCH "unknown"
#endif
#ifndef MRC_COMMIT_HASH
#define MRC_COMMIT_HASH "unknown"
#endif
#define MRC_BUILD_INFO MRC_COMMIT_TIMESTAMP " " MRC_COMMIT_BRANCH " " MRC_COMMIT_HASH

#ifdef MRB_USE_CXX_ABI
#define MRC_USE_CXX_ABI
Expand Down Expand Up @@ -99,6 +121,13 @@ typedef uint8_t mrc_bool;
# endif
#endif

/* mrc_int must be as wide as the VM's mrb_int and no wider: the pool literals
and the constant folding below are dumped for a target whose loader rejects
an IREP_TT_INT64 entry unless it was built with MRB_INT64 (src/load.c). */
#if defined(MRB_INT32) && !defined(MRC_INT32)
#define MRC_INT32 1
#endif

#if !defined(MRC_INT32)
#define MRC_INT64 1
#endif
Expand Down
1 change: 0 additions & 1 deletion vendor/mruby-compiler2/include/mrc_debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,3 @@ void mrc_debug_info_free(mrc_ccontext *c, mrc_irep_debug_info *d);
MRC_END_DECL

#endif /* MRC_DEBUG_H */

1 change: 1 addition & 0 deletions vendor/mruby-compiler2/include/mrc_diagnostic.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ typedef enum {
typedef struct mrc_diagnostic_list {
mrc_diagnostic_code code;
char *message;
const char *filename;
uint32_t line;
uint32_t column;
struct mrc_diagnostic_list *next;
Expand Down
14 changes: 10 additions & 4 deletions vendor/mruby-compiler2/include/mrc_dump.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ int mrc_dump_irep(mrc_ccontext *c, const mrc_irep *irep, uint8_t flags, uint8_t
/* Binary Format Version Major:Minor */
/* Major: Incompatible to prior versions */
/* Minor: Upper-compatible to prior versions */
#define RITE_BINARY_MAJOR_VER "03"
#define RITE_BINARY_MAJOR_VER "04"
#define RITE_BINARY_MINOR_VER "00"
#define RITE_BINARY_FORMAT_VER RITE_BINARY_MAJOR_VER RITE_BINARY_MINOR_VER
#if defined(RITE_COMPILER_NAME)
Expand All @@ -46,7 +46,7 @@ int mrc_dump_irep(mrc_ccontext *c, const mrc_irep *irep, uint8_t flags, uint8_t
#define RITE_PARSER_NAME "Prism"
#define RITE_COMPILER_VERSION "0000"

#define RITE_VM_VER "0300"
#define RITE_VM_VER "0400"

#define RITE_BINARY_EOF "END\0"
#define RITE_SECTION_IREP_IDENT "IREP"
Expand All @@ -56,6 +56,11 @@ int mrc_dump_irep(mrc_ccontext *c, const mrc_irep *irep, uint8_t flags, uint8_t
#define MRC_DUMP_DEFAULT_STR_LEN 128
#define MRC_DUMP_ALIGNMENT sizeof(uint32_t)

/* The RITE structs below are identical to the ones in mruby's
<mruby/dump.h>. Guard them so both headers can coexist in one
translation unit (e.g. the amalgamated build). */
#ifndef MRUBY_DUMP_H

/* binary header */
struct rite_binary_header {
uint8_t binary_ident[4]; /* Binary Identifier */
Expand Down Expand Up @@ -95,6 +100,8 @@ struct rite_binary_footer {
RITE_SECTION_HEADER;
};

#endif /* !MRUBY_DUMP_H */

static inline size_t
mrc_uint8_to_bin(uint8_t s, uint8_t *bin)
{
Expand Down Expand Up @@ -145,10 +152,9 @@ mrc_bin_to_uint8(const uint8_t *bin)
static inline const char*
mrc_description(void)
{
return MRC_VERSION " (" MRC_RELEASE_DATE ") Parser: " RITE_PARSER_NAME ", RITE: " RITE_BINARY_FORMAT_VER;
return "RITE" RITE_BINARY_FORMAT_VER " (" MRC_BUILD_INFO ") Parser: " RITE_PARSER_NAME "-" PRISM_VERSION;
}

MRC_END_DECL

#endif // MRC_DUMP_H

1 change: 0 additions & 1 deletion vendor/mruby-compiler2/include/mrc_endian.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,3 @@ check_little_endian(void)
MRC_END_DECL

#endif /* MRC_ENDIAN_H */

1 change: 1 addition & 0 deletions vendor/mruby-compiler2/include/mrc_irep.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ void mrc_irep_free(mrc_ccontext *c, mrc_irep *irep);
#define MRC_ASPEC_KEY(a) (((a) >> 2) & 0x1f)
#define MRC_ASPEC_KDICT(a) (((a) >> 1) & 0x1)
#define MRC_ASPEC_BLOCK(a) ((a) & 1)
#define MRC_ASPEC_NOBLOCK(a) (((a) >> 23) & 0x1)

MRC_END_DECL

Expand Down
Loading
Loading