Ruby added.

This commit is contained in:
Scott Duensing 2026-07-04 20:25:00 -05:00
parent ac2d587aa4
commit f8fb607cb6
697 changed files with 150284 additions and 22 deletions

7
.gitignore vendored
View file

@ -3,6 +3,13 @@
/bin/
/lib/
# Vendored-engine build output: mruby's Rake build and libssh2's CMake build emit whole
# trees (generated .c/.h, the mrbc tool, CMake cache) under their own build/ dirs.
/vendor/mruby/build/
/vendor/libssh2/build/
# ...and mruby's Rake drops a transient per-config lock next to the config (src/mruby/).
/src/mruby/*.lock
# Belt-and-suspenders: stray build artifacts from manual/ad-hoc compiles.
*.o
*.d

4
API.md
View file

@ -84,7 +84,7 @@ Share a function by name across contexts and engines.
|---|---|
| `calogExport(name: string, fn: fn)` | Publish function `fn` under a global `name`. |
| `calogUnexport(name: string)` | Remove an exported name. |
| `calogCall(name: string, ...args: any) -> any` | Call an exported function by name -- works in **every** engine. (An export is also reachable by its bare name -- `exportedFn(args)` -- on Lua/JS/Squirrel/s7, and on my-basic case-insensitively, since it uppercases identifiers; Wren and Berry always need `calogCall`.) |
| `calogCall(name: string, ...args: any) -> any` | Call an exported function by name -- works in **every** engine. (An export is also reachable by its bare name -- `exportedFn(args)` -- on Lua/JS/Squirrel/s7, on Ruby at top level (via `method_missing`), and on my-basic case-insensitively (it uppercases identifiers); Wren and Berry always need `calogCall`.) |
## fs
@ -208,7 +208,7 @@ out, or the close blocks until the task next returns to the runtime.
| Function | Description |
|---|---|
| `taskSpawn(engine: string, code: string) -> handle` | Run a code string on a named engine (`"lua"`, `"js"`, `"squirrel"`, `"mybasic"`, `"berry"`, `"s7"`, `"wren"`). |
| `taskSpawn(engine: string, code: string) -> handle` | Run a code string on a named engine (`"lua"`, `"js"`, `"squirrel"`, `"mybasic"`, `"berry"`, `"s7"`, `"wren"`, `"mruby"`). |
| `taskLoad(baseName: string) -> handle` | Launch a script *file* (engine chosen by extension). |
| `taskEval(handle: handle, code: string)` | Feed more code into a running task (runs on its thread). |
| `taskClose(handle: handle)` | Ask a task to stop (cooperative: sets its shutdown flag, then waits for its thread to exit). |

View file

@ -66,6 +66,10 @@ libraries below.
- **Berry** -- MIT License. Copyright (c) 2018-2022 Guan Wenliang and Berry
contributors. Notice in `vendor/berry/src/berry.h`.
- **mruby 4.0.0** (Ruby) -- MIT License. Copyright (c) 2010-2025 mruby developers.
`vendor/mruby/` (unmodified upstream; license in `vendor/mruby/LICENSE`, contributors
in `vendor/mruby/AUTHORS`). `libmruby.a` is generated by mruby's own Rake build (needs a
host Ruby + bison at build time); calog links the resulting static archive.
### Database, network, and cryptography libraries

View file

@ -27,8 +27,8 @@ LDFLAGS = $(SAN)
# Our headers: src/ plus the per-language subdirs. VPATH lets the object rules find
# a source by name without spelling out its directory.
INC = -Isrc -Isrc/lua -Isrc/mybasic -Isrc/squirrel -Isrc/js -Isrc/berry -Isrc/s7 -Isrc/wren -Ilibs
VPATH = src:src/lua:src/mybasic:src/squirrel:src/js:src/berry:src/s7:src/wren:libs:tests
INC = -Isrc -Isrc/lua -Isrc/mybasic -Isrc/squirrel -Isrc/js -Isrc/berry -Isrc/s7 -Isrc/wren -Isrc/mruby -Ilibs
VPATH = src:src/lua:src/mybasic:src/squirrel:src/js:src/berry:src/s7:src/wren:src/mruby:libs:tests
# --- vendored our-basic: calog's fork of MY-BASIC (see vendor/ourbasic/NOTICE) ---
MBDIR = vendor/ourbasic
@ -118,6 +118,23 @@ WRENFLAGS = -std=c99 -w -g -O1
WRENOBJ = obj/wren.o
WRENLIBS = -lm
# --- vendored mruby 4.0.0 (Ruby). UNLIKE every other engine, libmruby.a is GENERATED by mruby's
# own Rake build (needs a host Ruby >=2.5 + bison), not compiled from .c here. The embed gembox
# is the core language + runtime eval (mruby-compiler) + stdlib/math/metaprog, with no executables
# and no file/socket IO (calog provides those). MRB_INT64 keeps script integers 64-bit. Links -lm.
# The build config lives in src/mruby/ (calog-owned), NOT in vendor/mruby/, so re-vendoring a new
# mruby version cannot clobber it. ---
MRUBYDIR = vendor/mruby
# Both the static headers AND the build-generated ones (mruby/presym.h -- pre-interned symbols
# -- and mrbconf.h are emitted per-build under build/calog/include).
MRUBYINC = -I$(MRUBYDIR)/include -I$(MRUBYDIR)/build/calog/include
MRUBYCONF = $(CURDIR)/src/mruby/build_config.rb
MRUBYLIB = $(MRUBYDIR)/build/calog/lib/libmruby.a
MRUBYLIBS = -lm
$(MRUBYLIB): $(MRUBYCONF)
cd $(MRUBYDIR) && MRUBY_CONFIG=$(MRUBYCONF) ruby ./minirake -j4
# --- vendored SQLite (C amalgamation, single file). THREADSAFE=1 (serialized) because
# the DB natives run inline on many context threads. Links -lm -lpthread. ---
SQLITEDIR = vendor/sqlite
@ -135,19 +152,19 @@ ENETOBJ = $(foreach n,$(ENETNAMES),obj/enet_$(n).o)
BINS = bin/testBroker bin/testLua bin/testMyBasic bin/testPolyglot bin/testActor \
bin/testEngineLua bin/testEngineMyBasic bin/testSquirrel bin/testEngineSquirrel bin/testJs bin/testEngineJs \
bin/testEngineBerry bin/testEngineS7 bin/testEngineWren bin/testLoad bin/testDb bin/testNet bin/testTask bin/testExport bin/testJson bin/testTime bin/testFs bin/testCrypto bin/testKv bin/testTimer bin/testPubsub bin/testHttp bin/testHttps bin/embed bin/calog
bin/testEngineBerry bin/testEngineS7 bin/testEngineWren bin/testEngineMruby bin/testLoad bin/testDb bin/testNet bin/testTask bin/testExport bin/testJson bin/testTime bin/testFs bin/testCrypto bin/testKv bin/testTimer bin/testPubsub bin/testHttp bin/testHttps bin/embed bin/calog
all: $(BINS)
# ---- object rules, grouped by flag set (sources resolved via VPATH) ----
# strict C, no threads
STRICTOBJ = obj/broker.o obj/value.o obj/luaEngine.o obj/squirrelEngine.o obj/jsEngine.o obj/berryEngine.o obj/s7Engine.o obj/wrenEngine.o obj/testBroker.o
STRICTOBJ = obj/broker.o obj/value.o obj/luaEngine.o obj/squirrelEngine.o obj/jsEngine.o obj/berryEngine.o obj/s7Engine.o obj/wrenEngine.o obj/mrubyEngine.o obj/testBroker.o
$(STRICTOBJ): obj/%.o: %.c | obj
$(CC) $(COREFLAGS) $(INC) -c -o $@ $<
# strict C, threaded
THREADOBJ = obj/context.o obj/mybasicEngine.o obj/testActor.o obj/testEngineLua.o obj/testEngineSquirrel.o obj/testEngineJs.o obj/testEngineMyBasic.o obj/testEngineBerry.o obj/testEngineS7.o obj/testEngineWren.o obj/calogHandle.o obj/testDb.o obj/testNet.o obj/testTask.o obj/calogExport.o obj/testExport.o obj/calogJson.o obj/testJson.o obj/calogFs.o obj/testFs.o obj/calogTime.o obj/testTime.o obj/calogKv.o obj/testKv.o obj/testCrypto.o obj/calogTimer.o obj/testTimer.o obj/calogPubsub.o obj/testPubsub.o obj/testHttp.o obj/testSsh.o
THREADOBJ = obj/context.o obj/mybasicEngine.o obj/testActor.o obj/testEngineLua.o obj/testEngineSquirrel.o obj/testEngineJs.o obj/testEngineMyBasic.o obj/testEngineBerry.o obj/testEngineS7.o obj/testEngineWren.o obj/testEngineMruby.o obj/calogHandle.o obj/testDb.o obj/testNet.o obj/testTask.o obj/calogExport.o obj/testExport.o obj/calogJson.o obj/testJson.o obj/calogFs.o obj/testFs.o obj/calogTime.o obj/testTime.o obj/calogKv.o obj/testKv.o obj/testCrypto.o obj/calogTimer.o obj/testTimer.o obj/calogPubsub.o obj/testPubsub.o obj/testHttp.o obj/testSsh.o
$(THREADOBJ): obj/%.o: %.c | obj
$(CC) $(COREFLAGS) $(INC) -pthread -c -o $@ $<
@ -205,6 +222,12 @@ WRENADP = obj/wrenAdapter.o
$(WRENADP): obj/%.o: %.c | obj
$(CC) $(ADPFLAGS) $(INC) $(WRENINC) -c -o $@ $<
# relaxed C + mruby headers. Ordered after $(MRUBYLIB): mruby's Rake build emits generated
# headers (mruby/presym.h) under build/calog/include that the adapter includes.
MRUBYADP = obj/mrubyAdapter.o
$(MRUBYADP): obj/%.o: %.c | obj $(MRUBYLIB)
$(CC) $(ADPFLAGS) $(INC) $(MRUBYINC) -c -o $@ $<
# DB library adapter: relaxed C + SQLite headers, sqlite backend compiled in
DBADP = obj/calogDb.o
$(DBADP): obj/%.o: %.c | obj
@ -218,7 +241,7 @@ $(NETADP): obj/%.o: %.c | obj
# task library: strict C with every engine name compiled in (it references each engine
# vtable under its CALOG_WITH_* guard), so a task-using binary links all engine archives.
ENGINEDEFS = -DCALOG_WITH_LUA -DCALOG_WITH_JS -DCALOG_WITH_SQUIRREL -DCALOG_WITH_MYBASIC -DCALOG_WITH_BERRY -DCALOG_WITH_S7 -DCALOG_WITH_WREN
ENGINEDEFS = -DCALOG_WITH_LUA -DCALOG_WITH_JS -DCALOG_WITH_SQUIRREL -DCALOG_WITH_MYBASIC -DCALOG_WITH_BERRY -DCALOG_WITH_S7 -DCALOG_WITH_WREN -DCALOG_WITH_MRUBY
TASKADP = obj/calogTask.o
$(TASKADP): obj/%.o: %.c | obj
$(CC) $(COREFLAGS) $(INC) $(ENGINEDEFS) -pthread -c -o $@ $<
@ -271,7 +294,8 @@ obj/enet_%.o: $(ENETDIR)/%.c | obj
CALOGLIB = obj/value.o obj/broker.o obj/context.o \
obj/luaAdapter.o obj/luaEngine.o obj/jsAdapter.o obj/jsEngine.o \
obj/squirrelAdapter.o obj/squirrelEngine.o obj/mybasicAdapter.o obj/mybasicEngine.o \
obj/berryAdapter.o obj/berryEngine.o obj/s7Adapter.o obj/s7Engine.o obj/wrenAdapter.o obj/wrenEngine.o
obj/berryAdapter.o obj/berryEngine.o obj/s7Adapter.o obj/s7Engine.o obj/wrenAdapter.o obj/wrenEngine.o \
obj/mrubyAdapter.o obj/mrubyEngine.o
lib/libcalog.a: $(CALOGLIB) | lib
ar rcs $@ $^
@ -375,6 +399,9 @@ bin/testEngineS7: obj/testEngineS7.o lib/libcalog.a lib/libs7.a | bin
bin/testEngineWren: obj/testEngineWren.o lib/libcalog.a lib/libwren.a | bin
$(CC) $(LDFLAGS) -pthread -o $@ $^ $(WRENLIBS)
bin/testEngineMruby: obj/testEngineMruby.o lib/libcalog.a $(MRUBYLIB) | bin
$(CC) $(LDFLAGS) -pthread -o $@ $^ $(MRUBYLIBS)
# example host: embeds calog + JS via calog.h only, linking the two archives.
obj/embed.o: examples/embed.c src/calog.h | obj
$(CC) $(COREFLAGS) -Isrc -pthread -c -o $@ $<
@ -390,7 +417,7 @@ bin/embed: obj/embed.o lib/libcalog.a lib/libquickjs.a | bin
# it); SSLARCH follows the archives that reference it.
bin/calog: obj/calogMain.o \
obj/calogCrypto.o obj/calogDbFull.o obj/calogExport.o obj/calogFs.o obj/calogHttp.o obj/calogJson.o obj/calogKv.o obj/calogNet.o obj/calogPubsub.o obj/calogSsh.o obj/calogTask.o obj/calogTime.o obj/calogTimer.o obj/calogHandle.o \
lib/libcalog.a lib/liblua.a lib/libquickjs.a lib/libsquirrel.a lib/libmybasic.a lib/libberry.a lib/libs7.a lib/libwren.a \
lib/libcalog.a lib/liblua.a lib/libquickjs.a lib/libsquirrel.a lib/libmybasic.a lib/libberry.a lib/libs7.a lib/libwren.a $(MRUBYLIB) \
lib/libsqlite3.a lib/libenet.a $(LIBSSH2LIB) $(DBARCH) | bin
$(CC) $(LDFLAGS) -pthread -o $@ $(filter-out $(DBARCH),$^) -Wl,--start-group $(PGARCHIVES) -Wl,--end-group $(MYSQLARCH) $(SSLARCH) -lstdc++ -ldl -lm -lpthread
@ -429,12 +456,12 @@ static: bin/calogStatic
obj/testLoad.o: tests/testLoad.c src/calog.h | obj
$(CC) $(COREFLAGS) -Isrc -pthread $(ENGINEDEFS) -c -o $@ $<
bin/testLoad: obj/testLoad.o lib/libcalog.a lib/liblua.a lib/libquickjs.a lib/libsquirrel.a lib/libmybasic.a lib/libberry.a lib/libs7.a lib/libwren.a | bin
$(CC) $(LDFLAGS) -pthread -o $@ $^ $(LUALIBS) -lstdc++ -lm
bin/testLoad: obj/testLoad.o lib/libcalog.a lib/liblua.a lib/libquickjs.a lib/libsquirrel.a lib/libmybasic.a lib/libberry.a lib/libs7.a lib/libwren.a $(MRUBYLIB) | bin
$(CC) $(LDFLAGS) -pthread -o $@ $^ $(LUALIBS) -lstdc++ -lm $(MRUBYLIBS)
# task library test: the task lib names every engine, so (like testLoad) it links them all.
bin/testTask: obj/testTask.o $(TASKADP) obj/calogHandle.o lib/libcalog.a lib/liblua.a lib/libquickjs.a lib/libsquirrel.a lib/libmybasic.a lib/libberry.a lib/libs7.a lib/libwren.a | bin
$(CC) $(LDFLAGS) -pthread -o $@ $^ $(LUALIBS) -lstdc++ -lm
bin/testTask: obj/testTask.o $(TASKADP) obj/calogHandle.o lib/libcalog.a lib/liblua.a lib/libquickjs.a lib/libsquirrel.a lib/libmybasic.a lib/libberry.a lib/libs7.a lib/libwren.a $(MRUBYLIB) | bin
$(CC) $(LDFLAGS) -pthread -o $@ $^ $(LUALIBS) -lstdc++ -lm $(MRUBYLIBS)
# export library test: publish from Lua, call by bare name from Lua + via callExport from JS.
bin/testExport: obj/testExport.o obj/calogExport.o lib/libcalog.a lib/liblua.a lib/libquickjs.a lib/libsquirrel.a lib/libs7.a lib/libmybasic.a | bin
@ -483,7 +510,7 @@ obj bin lib:
test: all
./bin/testBroker && ./bin/testLua && ./bin/testMyBasic && ./bin/testPolyglot && \
./bin/testActor && ./bin/testEngineLua && ./bin/testEngineMyBasic && ./bin/testSquirrel && ./bin/testEngineSquirrel && \
./bin/testJs && ./bin/testEngineJs && ./bin/testEngineBerry && ./bin/testEngineS7 && ./bin/testEngineWren && ./bin/testLoad && ./bin/testDb && ./bin/testNet && ./bin/testTask && ./bin/testExport && ./bin/testJson && ./bin/testTime && ./bin/testFs && ./bin/testCrypto && ./bin/testKv && ./bin/testTimer && ./bin/testPubsub && ./bin/testHttp && ./bin/testHttps
./bin/testJs && ./bin/testEngineJs && ./bin/testEngineBerry && ./bin/testEngineS7 && ./bin/testEngineWren && ./bin/testEngineMruby && ./bin/testLoad && ./bin/testDb && ./bin/testNet && ./bin/testTask && ./bin/testExport && ./bin/testJson && ./bin/testTime && ./bin/testFs && ./bin/testCrypto && ./bin/testKv && ./bin/testTimer && ./bin/testPubsub && ./bin/testHttp && ./bin/testHttps
# ThreadSanitizer build of the actor core and the Lua engine path (cannot combine
# with ASan). Recompiled from source under TSan; the vendored Lua objects are
@ -566,6 +593,16 @@ tsanwren: | bin obj
setarch -R ./bin/testEngineWrenTsan
rm -f obj/wren.tsan.o
# ThreadSanitizer build of the mruby engine path. Unlike the other engines, mruby's VM is a
# separate Rake-built archive, so it links UN-sanitized (like tsanlibs with liblua.a) -- TSan
# instruments the calog adapter/engine/actor code, which is where the cross-context risk lives;
# each mrb_state is independent (one per thread), the concurrency gate mruby was chosen on.
tsanmruby: $(MRUBYLIB) | bin obj
$(CC) $(TSANFLAGS) $(INC) $(MRUBYINC) -o bin/testEngineMrubyTsan \
tests/testEngineMruby.c src/mruby/mrubyEngine.c src/mruby/mrubyAdapter.c $(TSANCORE) \
$(MRUBYLIB) $(MRUBYLIBS)
setarch -R ./bin/testEngineMrubyTsan
# ThreadSanitizer build of the concurrent libraries (timer's background thread, pubsub's
# callback fan-out, kv's shared store), each over a Lua context so callbacks marshal across
# threads. The unsanitized liblua.a links in fine (TSan instruments only the calog code).
@ -583,4 +620,4 @@ clean:
-include $(wildcard obj/*.d)
-include $(wildcard obj/rel/*.d)
.PHONY: all test tsan tsansq tsanjs tsanmb tsanberry tsans7 tsanwren tsanlibs clean
.PHONY: all test tsan tsansq tsanjs tsanmb tsanberry tsans7 tsanwren tsanmruby tsanlibs clean

View file

@ -4,7 +4,7 @@
calog embeds scripting into a C or C++ program. You register your native C functions
**once**, and they become callable from **any** embedded engine — Lua, JavaScript, Scheme,
Squirrel, Wren, Berry, or MY-BASIC — with values passed through a single canonical type. Add a new
Squirrel, Wren, Berry, Ruby, or MY-BASIC — with values passed through a single canonical type. Add a new
scripting language to your app by linking one more archive; your native functions don't
change.
@ -19,7 +19,7 @@ calogContextEval(ctx, "hostLog('hello from JavaScript, ' + 6 * 7)");
```
Swap `&calogJsEngine` for `&calogLuaEngine`, `&calogSquirrelEngine`,
`&calogS7Engine`, `&calogWrenEngine`, `&calogBerryEngine`, or `&calogMyBasicEngine` — nothing else changes.
`&calogS7Engine`, `&calogWrenEngine`, `&calogBerryEngine`, `&calogMrubyEngine`, or `&calogMyBasicEngine` — nothing else changes.
---
@ -59,6 +59,7 @@ Swap `&calogJsEngine` for `&calogLuaEngine`, `&calogSquirrelEngine`,
| Scheme | `calogS7Engine` | `.scm` | s7; 64-bit ints |
| Wren | `calogWrenEngine` | `.wren` | doubles only; call via `Calog.call(…)` |
| Berry | `calogBerryEngine` | `.be` | scalars + callbacks |
| Ruby | `calogMrubyEngine` | `.rb` | mruby; 64-bit ints; built by mruby's Rake |
A native can return a keyed `CalogValueT` record and **every** engine reads its fields with
native syntax (`user.name`, `user["name"]`, `(user "name")`), and a script can hand a

View file

@ -1029,3 +1029,52 @@ compile). Berry's `BE_BYTES_MAX_SIZE` was likewise raised from 32 kb to 256 MB.
**Verified**: `make test` (539 checks) with a `testForeignFunction` per engine and a
`testMapIngress` on s7 and Berry (the Berry one nests a list to exercise list ingress);
ASan-clean on every engine (retain/release balanced); gcc strict; per-engine `tsan*`.
## 19. mruby -- the eighth engine (Ruby)
**mruby** (`.rb`, `calogMrubyEngine`) is the first engine whose static library is not compiled from
vendored `.c` but **generated by the engine's own build**: mruby 4.0.0's Rake build (needs a host
Ruby + bison) emits `libmruby.a` from a trimmed embed gembox -- stdlib + math + metaprog (which
carries `mruby-compiler`, i.e. runtime `eval`) plus `mruby-bin-mrbc` as a *build-time* tool to
compile the Ruby-written stdlib into the archive; no bins, no file/socket IO. `MRB_INT64` keeps
script integers full 64-bit. The Makefile runs the Rake build as a prerequisite of the adapter
object, since mruby emits a per-build `mruby/presym.h` the adapter must include. Linked footprint is
~1.1 MB (QuickJS class -- not the CPython-scale bloat the feasibility study found real Ruby drags in).
Dispatch resolves two mruby facts. `mrb_func_t` carries **no user data**, so every native binds one
shared trampoline that recovers *which* native was called from the current method id (`mrb_get_mid`
-> `mrb_sym_name`); the context rides on **`mrb->ud`** (mrb_state's spare auxiliary pointer --
script-invisible, no global). Natives are public `Kernel` methods, so `cryptoUuid()` works bare.
Callables cross both ways with real Ruby semantics. A Ruby proc/lambda crossing *out* is GC-pinned
with `mrb_gc_register` behind `CalogFnT`, invoked with `mrb_funcall_argv(..., "call", ...)` (so a
Proc, a lambda, or a `Method` all work). A foreign `CalogFnT` crossing *in* becomes a **genuine Ruby
`Proc`** via `mrb_proc_new_cfunc_with_env` (the `CalogFnT` travels in the proc's cfunc env as a
cptr), so a script calls it `f.call(x)` / `f.(x)` and can pass it as a block -- no `.call`-method
wrapper like Wren, no `calogInvoke` helper like my-basic. As with Berry, that cfunc env has no
per-value finalizer, so foreign callables are tracked on the context and released at destroy;
marshalling is bracketed by `mrb_gc_arena_save`/`restore` so transient objects don't overflow the
arena.
Aggregates are `Array` <-> list and `Hash` <-> map (a keyed record's sequence part goes at integer
keys); strings are binary-safe (`mrb_str_new` carries a length). Bare-name **exports** resolve via
`Kernel#method_missing`: a top-level `exportedFn(args)` that is not a defined method is looked up in
the export registry and invoked -- but *only* when `self` is the main object (`mrb_obj_equal` against
`mrb_top_self`), so a missing method on any other receiver (`obj.foo`) stays a plain `NoMethodError`
and is never hijacked. This puts Ruby among the hook engines without a VM change -- its own
`method_missing` is the hook my-basic needed a fork to fake.
**IO by design.** Ruby's `File`/`IO`/`Socket` are left out (no `mruby-io`): scripts use calog's
`fs*`/`net*`/`http*` natives like every other engine, so all IO stays on one path. A partial `File`
shim would footgun (whole-file ops map to calog's `fs`, but the streaming object model does not), so
it is all-or-nothing and deferred; the adapter supplies only `puts`/`print`/`p` (to stdout).
mruby keeps no shared mutable process state -- one independent `mrb_state` per `mrb_open`, no GIL --
so contexts run in parallel, the concurrency gate mruby was chosen on (over MRI/CRuby and MicroPython,
which both fail it). Its Rake-built archive links un-sanitized, so `tsanmruby` instruments the
adapter/engine/actor code (like `tsanlibs` with Lua); each VM is single-threaded per instance.
**Verified**: `testEngineMruby` (13 checks -- natives, `Hash` egress/ingress, a foreign `Proc`, a
cross-thread lambda callback, the error handler, three concurrent `mrb_state`s), ASan-clean;
`tsanmruby` clean; cross-engine both ways (Ruby calling a Lua export, Lua invoking a Ruby lambda
export); `make test` 29/29.

View file

@ -33,6 +33,7 @@ Conventions every example follows:
| `squirrel.nut` | Squirrel: locals, a function, `foreach` over an array, a table, a small class |
| `mybasic.bas` | my-basic: variables, a `FOR..NEXT` sum, `IF..THEN..ELSE`, plus crypto + kv |
| `berry.be` | Berry (Python-like): a `def`, a list built with a `for`, a map, then json + uuid |
| `ruby.rb` | Ruby (mruby): a Range, `reduce` with a block, `select(&:even?)`, a Hash, then json + sha256 |
| `scheme.scm` | s7 Scheme: a recursive factorial, list build + map, string ops (all in one `(begin ...)`) |
| `wren.wren` | Wren: a class, a `List`, and every native reached via `Calog.call(name, [args])` |

View file

@ -0,0 +1,19 @@
# A guided tour of Ruby (mruby) running on calog.
# Demonstrates: a Range, reduce with a block, select with a symbol-to-proc, a Hash, then the
# jsonStringify/jsonParse and cryptoHashSha256 natives. Ruby's puts works; real file/socket IO
# is provided by calog's fs*/net* natives (not Ruby's stdlib) -- so scripts stay uniform.
# run: bin/calog examples/scripts/languages/ruby.rb
nums = (1..5).to_a
total = nums.reduce(0) { |acc, n| acc + n }
evens = nums.select(&:even?)
puts "nums=#{nums.inspect} total=#{total} evens=#{evens.inspect}"
user = { "name" => "ada", "age" => 36 }
calogPrint("user as JSON:", jsonStringify(user))
parsed = jsonParse('{"lang":"ruby","ints":[1,2,3]}')
calogPrint("parsed lang:", parsed["lang"], "| first int:", parsed["ints"][0])
calogPrint("sha256(calog):", cryptoHashSha256("calog"))
calogExit(0)

View file

@ -9,9 +9,11 @@
// (plain `export` is a JavaScript keyword; plain `call` is a my-basic keyword).
//
// On engines with a runtime unknown-name hook (Lua, Squirrel, JavaScript, s7), an exported
// name is ALSO reachable by its BARE name, e.g. `luaExample(1, 2)`. my-basic likewise bare-
// resolves a name called like a function, but CASE-INSENSITIVELY (it uppercases identifiers at
// parse time), so `luaExample(1, 2)` there matches the export ignoring case. Wren and Berry
// name is ALSO reachable by its BARE name, e.g. `luaExample(1, 2)`. Ruby resolves a bare name
// the same way via Kernel#method_missing, but only at TOP LEVEL (self is the main object, so a
// missing method on some other receiver -- obj.foo -- is never hijacked). my-basic likewise
// bare-resolves a name called like a function, but CASE-INSENSITIVELY (it uppercases identifiers
// at parse time), so `luaExample(1, 2)` there matches the export ignoring case. Wren and Berry
// resolve names statically and use calogCall('luaExample', ...). Resolution is dynamic: a name
// exported at any time becomes callable immediately, and calogUnexport takes effect at once.
//

View file

@ -69,6 +69,9 @@ static const TaskEngineT gTaskEngines[] = {
#endif
#ifdef CALOG_WITH_WREN
{ "wren", &calogWrenEngine },
#endif
#ifdef CALOG_WITH_MRUBY
{ "mruby", &calogMrubyEngine },
#endif
{ NULL, NULL }
};

View file

@ -203,6 +203,7 @@ extern const CalogEngineT calogMyBasicEngine;
extern const CalogEngineT calogBerryEngine;
extern const CalogEngineT calogS7Engine;
extern const CalogEngineT calogWrenEngine;
extern const CalogEngineT calogMrubyEngine;
// Register the built-in engines selected at build time, so calogContextLoad works
// without hand-registering each. Define CALOG_WITH_LUA / _JS / _SQUIRREL / _MYBASIC (in
@ -231,6 +232,9 @@ static inline void calogRegisterBuiltinEngines(CalogT *calog) {
#endif
#ifdef CALOG_WITH_WREN
calogRegisterEngine(calog, &calogWrenEngine);
#endif
#ifdef CALOG_WITH_MRUBY
calogRegisterEngine(calog, &calogMrubyEngine);
#endif
(void)calog; // no-op if the build selected no engines
}

View file

@ -93,7 +93,8 @@ static const CalogEngineT *const gEngines[] = {
&calogMyBasicEngine,
&calogBerryEngine,
&calogS7Engine,
&calogWrenEngine
&calogWrenEngine,
&calogMrubyEngine
};
// The built-in libraries, in registration order. One source of truth: main() registers every

30
src/mruby/build_config.rb Normal file
View file

@ -0,0 +1,30 @@
# calog's embed build config for mruby.
#
# Kept HERE, in src/mruby/ (NOT under vendor/mruby/), on purpose: it is calog-owned, so
# re-vendoring a new mruby version -- which replaces the whole vendor/mruby/ tree -- cannot
# overwrite or delete it. The Makefile points MRUBY_CONFIG at this file by absolute path and runs
# the build from the mruby tree, so `conf.gembox 'name'` resolves against vendor/mruby/mrbgems.
#
# Produces build/calog/lib/libmruby.a. Trimmed for embedding:
# - stdlib : Array/Hash/String/Enumerable/... extensions, Set, Fiber, Struct
# - stdlib-ext : sprintf, time, struct, data, random, pack
# - math : Math, Rational, Complex, bigint (arbitrary-precision integers)
# - metaprog : metaprogramming AND mruby-compiler (runtime eval of source strings)
# Deliberately excluded: the bin gems (no mrbc/mirb/mruby executables -- calog links only the
# library) and stdlib-io / mruby-io / mruby-socket (calog provides its own fs and net natives;
# the adapter supplies puts/print). MRB_INT64 keeps script integers full 64-bit to match calog.
MRuby::Build.new('calog') do |conf|
conf.toolchain :gcc
conf.cc.flags << '-O2'
conf.cc.defines << 'MRB_INT64'
conf.gembox 'stdlib'
conf.gembox 'stdlib-ext'
conf.gembox 'math'
conf.gembox 'metaprog'
# Build-time tool only: mrbc compiles the Ruby-written stdlib (mrblib/*.rb and each gem's
# *.rb) into libmruby.a. The executable is not linked into calog. It is the one bin gem the
# library build requires; the other bins (mirb/mruby/mrdb) are deliberately left out.
conf.gem core: 'mruby-bin-mrbc'
end

714
src/mruby/mrubyAdapter.c Normal file
View file

@ -0,0 +1,714 @@
// mrubyAdapter.c -- mruby (Ruby) engine adapter for the broker.
//
// Each exposed native is a Kernel method bound to one shared trampoline. mrb_func_t carries no
// userData, so the trampoline recovers the native's name from the current call's method id
// (mrb_get_mid) and the owning context from mrb->ud, then marshals the Ruby arguments to
// CalogValueT and dispatches through calogCall (honoring the actor route hook). Marshalling covers
// scalars and binary-safe strings; aggregates cross both ways (Array<->list, Hash<->map). Functions
// cross both ways too: a Ruby proc out becomes a refcounted CalogFnT pinned as a GC root
// (mrb_gc_register) and dropped on release; a foreign CalogFnT in becomes a real Ruby Proc
// (mrb_proc_new_cfunc_with_env) carrying the CalogFnT in its env -- the script calls it as f.call(x).
// Foreign functions are tracked on the context and released at destroy (a cfunc proc's env has no
// per-value finalizer). puts/print/p are provided (routed to stdout); there is no file/socket IO.
//
// Error model: on failure the trampoline raises an mruby exception (mrb_raise, which longjmps out
// of the VM) after freeing any CalogValueT it owns. GC-arena save/restore brackets marshalling so
// transient objects created here do not overflow the arena.
#define _POSIX_C_SOURCE 200809L
#include "mrubyAdapter.h"
#include <mruby.h>
#include <mruby/array.h>
#include <mruby/compile.h>
#include <mruby/error.h>
#include <mruby/hash.h>
#include <mruby/proc.h>
#include <mruby/string.h>
#include <mruby/variable.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MRUBY_FOREIGN_INITIAL 8
struct CalogMrubyT {
mrb_state *mrb;
CalogT *broker;
uint64_t ctxId;
CalogFnT **foreignFns; // foreign function values pushed into this VM
int32_t foreignCount;
int32_t foreignCap;
};
// Backs a CalogFnT exported from this VM: the owning context and the pinned Ruby callable
// (a Proc/Method), kept GC-reachable by mrb_gc_register until the CalogFnT is released.
typedef struct MrubyExportT {
CalogMrubyT *context;
mrb_value callable;
} MrubyExportT;
static int32_t mrubyCallableInvoke(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData);
static void mrubyCallableRelease(CalogFnT *callable);
static int32_t mrubyExportValue(CalogMrubyT *context, mrb_value callable, CalogFnT **out);
static mrb_value mrubyForeignCall(mrb_state *mrb, mrb_value self);
static int32_t mrubyFromValue(CalogMrubyT *context, const CalogValueT *value, mrb_value *out, int32_t depth);
static int32_t mrubyInvokeArgs(CalogMrubyT *context, CalogFnT *callable, mrb_value *argv, mrb_int argc, mrb_value *out, char *errbuf, size_t errcap);
static mrb_value mrubyMethodMissing(mrb_state *mrb, mrb_value self);
static mrb_value mrubyP(mrb_state *mrb, mrb_value self);
static mrb_value mrubyPrint(mrb_state *mrb, mrb_value self);
static mrb_value mrubyPuts(mrb_state *mrb, mrb_value self);
static int32_t mrubyToValue(CalogMrubyT *context, mrb_value value, CalogValueT *out, int32_t depth);
static int32_t mrubyTrackForeign(CalogMrubyT *context, CalogFnT *callable);
static mrb_value mrubyTrampoline(mrb_state *mrb, mrb_value self);
int32_t calogMrubyCreate(CalogMrubyT **out, CalogT *broker, uint64_t ctxId) {
CalogMrubyT *context;
mrb_state *mrb;
*out = NULL;
context = (CalogMrubyT *)calloc(1, sizeof(*context));
if (context == NULL) {
return calogErrOomE;
}
mrb = mrb_open();
if (mrb == NULL) {
free(context);
return calogErrOomE;
}
context->mrb = mrb;
context->broker = broker;
context->ctxId = ctxId;
mrb->ud = context; // the trampoline recovers the context from here
// Ruby ergonomics without pulling mruby-io: puts/print/p route to stdout. Defined on Kernel
// so a bare `puts "x"` works at top level (calog scripts still use fs*/net* for real IO).
mrb_define_method(mrb, mrb->kernel_module, "puts", mrubyPuts, MRB_ARGS_ANY());
mrb_define_method(mrb, mrb->kernel_module, "print", mrubyPrint, MRB_ARGS_ANY());
mrb_define_method(mrb, mrb->kernel_module, "p", mrubyP, MRB_ARGS_ANY());
// Bare-name export resolution: a top-level `exportedFn(args)` that is not a defined method
// resolves to a broker export (see mrubyMethodMissing), like the hook engines.
mrb_define_method(mrb, mrb->kernel_module, "method_missing", mrubyMethodMissing, MRB_ARGS_ANY());
*out = context;
return calogOkE;
}
static int32_t mrubyCallableInvoke(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData) {
MrubyExportT *export;
CalogMrubyT *context;
mrb_state *mrb;
mrb_value *argv;
mrb_value ret;
int arena;
int32_t index;
int32_t status;
export = (MrubyExportT *)userData;
context = export->context;
mrb = context->mrb;
calogValueNil(result);
argv = NULL;
if (argCount > 0) {
argv = (mrb_value *)calloc((size_t)argCount, sizeof(mrb_value));
if (argv == NULL) {
return calogFail(result, calogErrOomE, "out of memory calling mruby callable");
}
}
arena = mrb_gc_arena_save(mrb);
for (index = 0; index < argCount; index++) {
status = mrubyFromValue(context, &args[index], &argv[index], 0);
if (status != calogOkE) {
mrb_gc_arena_restore(mrb, arena);
free(argv);
return calogFail(result, status, "failed to marshal argument into mruby");
}
}
ret = mrb_funcall_argv(mrb, export->callable, mrb_intern_lit(mrb, "call"), (mrb_int)argCount, argv);
free(argv);
if (mrb->exc != NULL) {
mrb_value exc;
mrb_value message;
const char *text;
exc = mrb_obj_value(mrb->exc);
mrb->exc = NULL;
message = mrb_funcall_argv(mrb, exc, mrb_intern_lit(mrb, "message"), 0, NULL);
text = mrb_string_p(message) ? RSTRING_PTR(message) : "mruby callable raised";
status = calogFail(result, calogErrArgE, text);
mrb_gc_arena_restore(mrb, arena);
return status;
}
status = mrubyToValue(context, ret, result, 0);
mrb_gc_arena_restore(mrb, arena);
return status;
}
static void mrubyCallableRelease(CalogFnT *callable) {
MrubyExportT *export;
export = (MrubyExportT *)calogFnUserData(callable);
mrb_gc_unregister(export->context->mrb, export->callable);
free(export);
}
void calogMrubyDestroy(CalogMrubyT *context) {
int32_t index;
if (context == NULL) {
return;
}
// Release the foreign function values pushed into this VM (see mrubyTrackForeign): a cfunc
// proc's env has no per-value finalizer, so they are held until the context is destroyed.
for (index = 0; index < context->foreignCount; index++) {
calogFnRelease(context->foreignFns[index]);
}
free(context->foreignFns);
if (context->mrb != NULL) {
mrb_close(context->mrb);
}
free(context);
}
int32_t calogMrubyExport(CalogMrubyT *context, const char *name, CalogFnT **out) {
mrb_state *mrb;
mrb_value self;
mrb_value method;
mrb_value sym;
int arena;
int32_t status;
mrb = context->mrb;
*out = NULL;
// Object#method returns a Method for a top-level `def name` (public or private). A Proc/lambda
// held in a global ($name) also resolves through method_missing/global lookup below.
self = mrb_top_self(mrb);
sym = mrb_symbol_value(mrb_intern_cstr(mrb, name));
arena = mrb_gc_arena_save(mrb);
method = mrb_funcall_argv(mrb, self, mrb_intern_lit(mrb, "method"), 1, &sym);
if (mrb->exc != NULL) {
mrb->exc = NULL;
mrb_gc_arena_restore(mrb, arena);
return calogErrNotFoundE;
}
status = mrubyExportValue(context, method, out);
mrb_gc_arena_restore(mrb, arena);
return status;
}
static int32_t mrubyExportValue(CalogMrubyT *context, mrb_value callable, CalogFnT **out) {
mrb_state *mrb;
MrubyExportT *export;
int32_t status;
mrb = context->mrb;
*out = NULL;
export = (MrubyExportT *)malloc(sizeof(*export));
if (export == NULL) {
return calogErrOomE;
}
export->context = context;
export->callable = callable;
// Pin the callable as a GC root so it survives until the CalogFnT is released.
mrb_gc_register(mrb, callable);
status = calogFnCreate(out, context->broker, mrubyCallableInvoke, export, mrubyCallableRelease, context->ctxId);
if (status != calogOkE) {
mrb_gc_unregister(mrb, callable);
free(export);
return status;
}
return calogOkE;
}
int32_t calogMrubyExpose(CalogMrubyT *context, const char *name) {
mrb_state *mrb;
mrb = context->mrb;
if (calogLookup(context->broker, name) == NULL) {
return calogErrNotFoundE;
}
// A public Kernel method routed to the shared trampoline, so `name(args)` works at top level
// in any context. The trampoline recovers `name` from the call's method id.
mrb_define_method(mrb, mrb->kernel_module, name, mrubyTrampoline, MRB_ARGS_ANY());
return calogOkE;
}
// Call target for a foreign CalogFnT pushed into mruby as a Proc. The CalogFnT travels in the
// proc's cfunc env (slot 0, a cptr); the context comes from mrb->ud.
static mrb_value mrubyForeignCall(mrb_state *mrb, mrb_value self) {
CalogMrubyT *context;
CalogFnT *callable;
mrb_value *argv;
mrb_int argc;
mrb_value out;
int arena;
int32_t status;
char message[CALOG_ERR_MSG_CAP];
(void)self;
context = (CalogMrubyT *)mrb->ud;
callable = (CalogFnT *)mrb_cptr(mrb_proc_cfunc_env_get(mrb, 0));
mrb_get_args(mrb, "*", &argv, &argc);
arena = mrb_gc_arena_save(mrb);
status = mrubyInvokeArgs(context, callable, argv, argc, &out, message, sizeof(message));
mrb_gc_arena_restore(mrb, arena);
if (status != calogOkE) {
mrb_raise(mrb, E_RUNTIME_ERROR, message);
}
return out;
}
static int32_t mrubyFromValue(CalogMrubyT *context, const CalogValueT *value, mrb_value *out, int32_t depth) {
mrb_state *mrb;
mrb = context->mrb;
*out = mrb_nil_value();
if (depth >= CALOG_MAX_DEPTH) {
return calogErrDepthE;
}
switch (value->type) {
case calogNilE:
return calogOkE;
case calogBoolE:
*out = mrb_bool_value(value->as.b);
return calogOkE;
case calogIntE:
*out = mrb_int_value(mrb, (mrb_int)value->as.i);
return calogOkE;
case calogRealE:
*out = mrb_float_value(mrb, (mrb_float)value->as.r);
return calogOkE;
case calogStringE:
*out = mrb_str_new(mrb, value->as.s.bytes, (mrb_int)value->as.s.length);
return calogOkE;
case calogAggE: {
CalogAggT *aggregate;
int64_t index;
int32_t status;
mrb_value child;
aggregate = value->as.agg;
if (calogAggIsKeyed(aggregate)) {
mrb_value map;
map = mrb_hash_new(mrb);
for (index = 0; index < aggregate->arrayCount; index++) {
status = mrubyFromValue(context, &aggregate->array[index], &child, depth + 1);
if (status != calogOkE) {
return status;
}
mrb_hash_set(mrb, map, mrb_int_value(mrb, (mrb_int)index), child);
}
for (index = 0; index < aggregate->pairCount; index++) {
mrb_value key;
status = mrubyFromValue(context, &aggregate->pairs[index].key, &key, depth + 1);
if (status != calogOkE) {
return status;
}
status = mrubyFromValue(context, &aggregate->pairs[index].value, &child, depth + 1);
if (status != calogOkE) {
return status;
}
mrb_hash_set(mrb, map, key, child);
}
*out = map;
return calogOkE;
}
*out = mrb_ary_new_capa(mrb, (mrb_int)aggregate->arrayCount);
for (index = 0; index < aggregate->arrayCount; index++) {
status = mrubyFromValue(context, &aggregate->array[index], &child, depth + 1);
if (status != calogOkE) {
return status;
}
mrb_ary_push(mrb, *out, child);
}
return calogOkE;
}
case calogFnE: {
// A foreign callable becomes a real Ruby Proc carrying the CalogFnT in its env;
// the script calls it as f.call(x) / f.(x). Tracked on the context and released at
// destroy (a cfunc proc's env has no per-value finalizer).
mrb_value env[1];
if (mrubyTrackForeign(context, value->as.fn) != calogOkE) {
return calogErrOomE;
}
env[0] = mrb_cptr_value(mrb, value->as.fn);
*out = mrb_obj_value(mrb_proc_new_cfunc_with_env(mrb, mrubyForeignCall, 1, env));
calogFnRetain(value->as.fn);
return calogOkE;
}
}
return calogErrTypeE;
}
// Marshal argv[0..argc) into CalogValueT, invoke `callable`, and marshal the result into *out.
// Non-raising: returns calogOkE (out set) or an error, copying a message into errbuf so the caller
// can release its own references before raising (the mruby raise longjmps out).
static int32_t mrubyInvokeArgs(CalogMrubyT *context, CalogFnT *callable, mrb_value *argv, mrb_int argc, mrb_value *out, char *errbuf, size_t errcap) {
CalogValueT *args;
CalogValueT result;
mrb_int index;
int32_t status;
*out = mrb_nil_value();
args = NULL;
if (argc > 0) {
args = (CalogValueT *)calloc((size_t)argc, sizeof(CalogValueT));
if (args == NULL) {
snprintf(errbuf, errcap, "out of memory marshalling arguments");
return calogErrOomE;
}
}
for (index = 0; index < argc; index++) {
status = mrubyToValue(context, argv[index], &args[index], 0);
if (status != calogOkE) {
mrb_int cleanup;
for (cleanup = 0; cleanup < index; cleanup++) {
calogValueFree(&args[cleanup]);
}
free(args);
snprintf(errbuf, errcap, "failed to marshal an argument");
return status;
}
}
status = calogFnInvoke(callable, args, (int32_t)argc, &result);
for (index = 0; index < argc; index++) {
calogValueFree(&args[index]);
}
free(args);
if (status != calogOkE) {
snprintf(errbuf, errcap, "%s", (result.type == calogStringE) ? result.as.s.bytes : "call failed");
calogValueFree(&result);
return status;
}
status = mrubyFromValue(context, &result, out, 0);
calogValueFree(&result);
if (status != calogOkE) {
snprintf(errbuf, errcap, "failed to marshal the result");
}
return status;
}
// Kernel#method_missing: a bare name called at TOP LEVEL that is not a defined method may be a
// broker export. Resolve and invoke it -- but only when self is the top-level main object, so a
// missing method on any other receiver (obj.foo) stays a NoMethodError and is never hijacked.
// This gives Ruby the bare-name export resolution the hook engines have (no VM change needed).
static mrb_value mrubyMethodMissing(mrb_state *mrb, mrb_value self) {
CalogMrubyT *context;
mrb_value *argv;
mrb_int argc;
mrb_sym missing;
const char *name;
CalogValueT nameArg;
CalogValueT resolved;
mrb_value out;
int arena;
int32_t status;
char message[CALOG_ERR_MSG_CAP];
context = (CalogMrubyT *)mrb->ud;
mrb_get_args(mrb, "*", &argv, &argc); // argv[0] is the method name (a Symbol), rest are args
if (argc < 1 || !mrb_symbol_p(argv[0])) {
mrb_raise(mrb, E_NOMETHOD_ERROR, "method_missing without a method name");
}
missing = mrb_symbol(argv[0]);
if (!mrb_obj_equal(mrb, self, mrb_top_self(mrb))) {
mrb_raisef(mrb, E_NOMETHOD_ERROR, "undefined method '%n'", missing);
}
name = mrb_sym_name(mrb, missing);
if (calogValueString(&nameArg, name, (int64_t)strlen(name)) != calogOkE) {
mrb_raisef(mrb, E_NOMETHOD_ERROR, "undefined method '%n'", missing);
}
calogValueNil(&resolved);
calogCall(context->broker, "__calogExportResolve", &nameArg, 1, &resolved);
calogValueFree(&nameArg);
if (resolved.type != calogFnE) {
calogValueFree(&resolved);
mrb_raisef(mrb, E_NOMETHOD_ERROR, "undefined method '%n'", missing);
}
// It is an export: invoke with the remaining args. Keep our resolved reference across the
// invoke (guards against a concurrent unexport), release it, THEN raise on failure -- so the
// reference never leaks on the raise path.
arena = mrb_gc_arena_save(mrb);
status = mrubyInvokeArgs(context, resolved.as.fn, argv + 1, argc - 1, &out, message, sizeof(message));
calogValueFree(&resolved);
mrb_gc_arena_restore(mrb, arena);
if (status != calogOkE) {
mrb_raise(mrb, E_RUNTIME_ERROR, message);
}
return out;
}
static mrb_value mrubyP(mrb_state *mrb, mrb_value self) {
mrb_value *argv;
mrb_int argc;
mrb_int index;
(void)self;
mrb_get_args(mrb, "*", &argv, &argc);
for (index = 0; index < argc; index++) {
mrb_value text;
text = mrb_inspect(mrb, argv[index]);
fwrite(RSTRING_PTR(text), 1, (size_t)RSTRING_LEN(text), stdout);
fputc('\n', stdout);
}
if (argc == 1) {
return argv[0];
}
return mrb_nil_value();
}
static mrb_value mrubyPrint(mrb_state *mrb, mrb_value self) {
mrb_value *argv;
mrb_int argc;
mrb_int index;
(void)self;
mrb_get_args(mrb, "*", &argv, &argc);
for (index = 0; index < argc; index++) {
mrb_value text;
text = mrb_obj_as_string(mrb, argv[index]);
fwrite(RSTRING_PTR(text), 1, (size_t)RSTRING_LEN(text), stdout);
}
return mrb_nil_value();
}
static mrb_value mrubyPuts(mrb_state *mrb, mrb_value self) {
mrb_value *argv;
mrb_int argc;
mrb_int index;
(void)self;
mrb_get_args(mrb, "*", &argv, &argc);
if (argc == 0) {
fputc('\n', stdout);
return mrb_nil_value();
}
for (index = 0; index < argc; index++) {
mrb_value text;
text = mrb_obj_as_string(mrb, argv[index]);
fwrite(RSTRING_PTR(text), 1, (size_t)RSTRING_LEN(text), stdout);
fputc('\n', stdout);
}
return mrb_nil_value();
}
int32_t calogMrubyRun(CalogMrubyT *context, const char *source) {
mrb_state *mrb;
int arena;
mrb = context->mrb;
arena = mrb_gc_arena_save(mrb);
mrb_load_string(mrb, source);
if (mrb->exc != NULL) {
mrb_value exc;
mrb_value text;
exc = mrb_obj_value(mrb->exc);
mrb->exc = NULL;
text = mrb_funcall_argv(mrb, exc, mrb_intern_lit(mrb, "inspect"), 0, NULL);
fprintf(stderr, "mruby error: %s\n", mrb_string_p(text) ? RSTRING_PTR(text) : "(unknown)");
mrb_gc_arena_restore(mrb, arena);
return calogErrArgE;
}
mrb_gc_arena_restore(mrb, arena);
return calogOkE;
}
static int32_t mrubyToValue(CalogMrubyT *context, mrb_value value, CalogValueT *out, int32_t depth) {
mrb_state *mrb;
mrb = context->mrb;
calogValueNil(out);
if (depth >= CALOG_MAX_DEPTH) {
return calogErrDepthE;
}
if (mrb_nil_p(value)) {
return calogOkE;
}
switch (mrb_type(value)) {
case MRB_TT_TRUE:
calogValueBool(out, true);
return calogOkE;
case MRB_TT_FALSE:
calogValueBool(out, false);
return calogOkE;
case MRB_TT_INTEGER:
calogValueInt(out, (int64_t)mrb_integer(value));
return calogOkE;
case MRB_TT_FLOAT:
calogValueReal(out, (double)mrb_float(value));
return calogOkE;
case MRB_TT_STRING:
return calogValueString(out, RSTRING_PTR(value), (int64_t)RSTRING_LEN(value));
case MRB_TT_ARRAY: {
CalogAggT *aggregate;
int32_t status;
mrb_int index;
mrb_int count;
status = calogAggCreate(&aggregate, calogListE);
if (status != calogOkE) {
return status;
}
count = RARRAY_LEN(value);
for (index = 0; index < count; index++) {
CalogValueT element;
status = mrubyToValue(context, mrb_ary_ref(mrb, value, index), &element, depth + 1);
if (status != calogOkE) {
calogAggFree(aggregate);
return status;
}
status = calogAggPush(aggregate, &element);
if (status != calogOkE) {
calogValueFree(&element);
calogAggFree(aggregate);
return status;
}
}
calogValueAgg(out, aggregate);
return calogOkE;
}
case MRB_TT_HASH: {
CalogAggT *aggregate;
mrb_value keys;
int32_t status;
mrb_int index;
mrb_int count;
status = calogAggCreate(&aggregate, calogMapE);
if (status != calogOkE) {
return status;
}
keys = mrb_hash_keys(mrb, value);
count = RARRAY_LEN(keys);
for (index = 0; index < count; index++) {
mrb_value rubyKey;
CalogValueT key;
CalogValueT element;
rubyKey = mrb_ary_ref(mrb, keys, index);
status = mrubyToValue(context, rubyKey, &key, depth + 1);
if (status != calogOkE) {
calogAggFree(aggregate);
return status;
}
status = mrubyToValue(context, mrb_hash_get(mrb, value, rubyKey), &element, depth + 1);
if (status != calogOkE) {
calogValueFree(&key);
calogAggFree(aggregate);
return status;
}
status = calogAggSet(aggregate, &key, &element);
if (status != calogOkE) {
calogValueFree(&key);
calogValueFree(&element);
calogAggFree(aggregate);
return status;
}
}
calogValueAgg(out, aggregate);
return calogOkE;
}
case MRB_TT_PROC: {
CalogFnT *callable;
int32_t status;
status = mrubyExportValue(context, value, &callable);
if (status != calogOkE) {
return status;
}
calogValueFn(out, callable);
return calogOkE;
}
default:
break;
}
// Other reference types (symbols, objects, ranges, ...) have no CalogValueT equivalent.
return calogErrUnsupportedE;
}
// Record a foreign function pushed into this VM so it is released at destroy (a cfunc proc's env
// has no per-value finalizer to release it when the proc is collected).
static int32_t mrubyTrackForeign(CalogMrubyT *context, CalogFnT *callable) {
if (context->foreignCount == context->foreignCap) {
int32_t newCap;
CalogFnT **resized;
newCap = (context->foreignCap == 0) ? MRUBY_FOREIGN_INITIAL : context->foreignCap * CALOG_GROWTH_FACTOR;
resized = (CalogFnT **)realloc(context->foreignFns, (size_t)newCap * sizeof(CalogFnT *));
if (resized == NULL) {
return calogErrOomE;
}
context->foreignFns = resized;
context->foreignCap = newCap;
}
context->foreignFns[context->foreignCount] = callable;
context->foreignCount++;
return calogOkE;
}
static mrb_value mrubyTrampoline(mrb_state *mrb, mrb_value self) {
CalogMrubyT *context;
const char *name;
mrb_value *argv;
mrb_int argc;
CalogValueT *args;
CalogValueT result;
mrb_value out;
int arena;
mrb_int index;
int32_t status;
(void)self;
context = (CalogMrubyT *)mrb->ud;
name = mrb_sym_name(mrb, mrb_get_mid(mrb)); // which exposed native was called
mrb_get_args(mrb, "*", &argv, &argc);
args = NULL;
if (argc > 0) {
args = (CalogValueT *)calloc((size_t)argc, sizeof(CalogValueT));
if (args == NULL) {
mrb_raise(mrb, E_RUNTIME_ERROR, "out of memory marshalling native arguments");
}
}
arena = mrb_gc_arena_save(mrb);
for (index = 0; index < argc; index++) {
status = mrubyToValue(context, argv[index], &args[index], 0);
if (status != calogOkE) {
mrb_int cleanup;
for (cleanup = 0; cleanup < index; cleanup++) {
calogValueFree(&args[cleanup]);
}
free(args);
mrb_raise(mrb, E_TYPE_ERROR, "failed to marshal a native argument");
}
}
status = calogCall(context->broker, name, args, (int32_t)argc, &result);
for (index = 0; index < argc; index++) {
calogValueFree(&args[index]);
}
free(args);
if (status != calogOkE) {
char message[CALOG_ERR_MSG_CAP];
snprintf(message, sizeof(message), "%s", (result.type == calogStringE) ? result.as.s.bytes : "native call failed");
calogValueFree(&result);
mrb_raise(mrb, E_RUNTIME_ERROR, message);
}
status = mrubyFromValue(context, &result, &out, 0);
calogValueFree(&result);
mrb_gc_arena_restore(mrb, arena);
if (status != calogOkE) {
mrb_raise(mrb, E_TYPE_ERROR, "failed to marshal the native result");
}
return out;
}

28
src/mruby/mrubyAdapter.h Normal file
View file

@ -0,0 +1,28 @@
// mrubyAdapter.h -- mruby (Ruby) engine adapter for the broker.
//
// Exposes broker-registered natives into an mruby VM -- each becomes a Kernel method routed
// through one trampoline that recovers its name from the call's method id (mrb_func_t carries no
// userData) and the context from mrb->ud. Marshals values between mruby and CalogValueT by value:
// scalars, binary-safe strings, Array<->list, Hash<->map. A Ruby proc crossing OUT becomes a
// refcounted CalogFnT (GC-pinned with mrb_gc_register, dropped on release); a foreign CalogFnT
// crossing IN becomes a real Ruby Proc (mrb_proc_new_cfunc_with_env) the script calls as f.call(x)
// / f.(x). Ruby file/socket IO is intentionally absent -- scripts use calog's fs*/net* natives; the
// adapter supplies only puts/print/p (routed to stdout).
//
// Lifetime note (as with Berry): release every CalogFnT obtained from calogMrubyExport (and drop
// every function value marshalled out) BEFORE calogMrubyDestroy, since the release touches the VM.
#ifndef MRUBY_ADAPTER_H
#define MRUBY_ADAPTER_H
#include "calogInternal.h"
typedef struct CalogMrubyT CalogMrubyT;
int32_t calogMrubyCreate(CalogMrubyT **out, CalogT *broker, uint64_t ctxId);
void calogMrubyDestroy(CalogMrubyT *context);
int32_t calogMrubyExport(CalogMrubyT *context, const char *name, CalogFnT **out);
int32_t calogMrubyExpose(CalogMrubyT *context, const char *name);
int32_t calogMrubyRun(CalogMrubyT *context, const char *source);
#endif

61
src/mruby/mrubyEngine.c Normal file
View file

@ -0,0 +1,61 @@
// mrubyEngine.c -- bridges the mruby adapter to the actor layer's CalogEngineT vtable.
//
// Every hook runs on the owning context's thread (createInterpreter, runSource,
// destroyInterpreter), confining the mruby VM (one mrb_state) to one thread. createInterpreter
// builds the VM and exposes the registered natives; runSource evaluates a script and reports
// failure through the single error channel (result).
#include "calogInternal.h"
#include "mrubyAdapter.h"
static int32_t mrubyEngineCreate(CalogContextT *context, void **interpOut);
static void mrubyEngineDestroy(void *interp);
static int32_t mrubyEngineRun(void *interp, const char *source, CalogValueT *result);
static void mrubyExposeVisitor(const CalogEntryT *entry, void *ud);
static const char *const mrubyExtensions[] = { "rb", NULL };
const CalogEngineT calogMrubyEngine = {
"mruby",
mrubyExtensions,
mrubyEngineCreate,
mrubyEngineDestroy,
mrubyEngineRun
};
static int32_t mrubyEngineCreate(CalogContextT *context, void **interpOut) {
CalogMrubyT *rb;
int32_t status;
*interpOut = NULL;
status = calogMrubyCreate(&rb, calogContextBroker(context), calogContextId(context));
if (status != calogOkE) {
return status;
}
calogForEach(calogContextBroker(context), mrubyExposeVisitor, rb);
*interpOut = rb;
return calogOkE;
}
static void mrubyEngineDestroy(void *interp) {
calogMrubyDestroy((CalogMrubyT *)interp);
}
static int32_t mrubyEngineRun(void *interp, const char *source, CalogValueT *result) {
int32_t status;
calogValueNil(result);
status = calogMrubyRun((CalogMrubyT *)interp, source);
if (status != calogOkE) {
return calogFail(result, status, "mruby script failed");
}
return calogOkE;
}
static void mrubyExposeVisitor(const CalogEntryT *entry, void *ud) {
calogMrubyExpose((CalogMrubyT *)ud, entry->name);
}

403
tests/testEngineMruby.c Normal file
View file

@ -0,0 +1,403 @@
// testEngineMruby.c -- mruby on a context thread, driven the host way: register natives,
// open a context, fire-and-forget a script, and calogPump on the host thread. Verifies
// host-thread dispatch, the inline escape hatch, the cross-thread callback, aggregates both
// ways, a foreign function value, the error handler, and concurrent contexts (N mrb_states).
#define _POSIX_C_SOURCE 200809L
#include "calog.h"
#include <stdatomic.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define CHECK(cond, msg) checkImpl((cond), (msg), __FILE__, __LINE__)
#define PUMP_LIMIT 4000
static CalogT *calog = NULL;
static _Atomic int64_t reportedValue = 0;
static _Atomic uint64_t reportedCtxId = 0xFFFFu;
static _Atomic uint64_t inlineCtxId = 0xFFFFu;
static _Atomic int32_t bumpCount = 0;
static _Atomic bool scriptDone = false;
static _Atomic int32_t errorCount = 0;
static _Atomic uint64_t errorCtxId = 0;
static CalogFnT *_Atomic storedCb = NULL;
static char storedName[32] = { 0 };
static _Atomic int32_t nameLen = -1;
static int32_t testsRun = 0;
static int32_t testsFailed = 0;
static void checkImpl(bool condition, const char *message, const char *file, int32_t line);
static int32_t nativeAdd(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData);
static int32_t nativeBump(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData);
static int32_t nativeDone(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData);
static int32_t nativeGetAdder(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData);
static int32_t nativeMakeUser(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData);
static int32_t nativeMapAge(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData);
static int32_t nativeReport(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData);
static int32_t nativeReportInline(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData);
static int32_t nativeReportName(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData);
static int32_t nativeSetCb(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData);
static void onError(uint64_t contextId, const char *message, void *userData);
static void pumpUntilDone(void);
static void testConcurrentContexts(void);
static void testCrossThreadCallback(void);
static void testForeignFunction(void);
static void testHostAndInlineNatives(void);
static void testMapIngress(void);
static void testMaterializedRecord(void);
static void testScriptError(void);
static void checkImpl(bool condition, const char *message, const char *file, int32_t line) {
testsRun++;
if (!condition) {
testsFailed++;
printf("FAIL %s:%d %s\n", file, line, message);
}
}
static int32_t nativeAdd(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData) {
(void)userData;
calogValueNil(result);
if (argCount != 2 || args[0].type != calogIntE || args[1].type != calogIntE) {
return calogFail(result, calogErrArgE, "add expects two integers");
}
calogValueInt(result, args[0].as.i + args[1].as.i);
return calogOkE;
}
static int32_t nativeBump(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData) {
(void)args;
(void)argCount;
(void)userData;
atomic_fetch_add(&bumpCount, 1);
calogValueNil(result);
return calogOkE;
}
static int32_t nativeDone(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData) {
(void)args;
(void)argCount;
(void)userData;
atomic_store(&scriptDone, true);
calogValueNil(result);
return calogOkE;
}
static int32_t nativeGetAdder(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData) {
CalogFnT *callable;
int32_t status;
(void)args;
(void)argCount;
(void)userData;
calogValueNil(result);
// A host-owned function value handed to the script; calling it routes back here.
status = calogFnFromNative(&callable, calog, nativeAdd, NULL);
if (status != calogOkE) {
return calogFail(result, status, "getAdder could not allocate");
}
calogValueFn(result, callable);
return calogOkE;
}
static int32_t nativeMakeUser(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData) {
CalogAggT *user;
CalogValueT key;
CalogValueT val;
int32_t status;
(void)args;
(void)argCount;
(void)userData;
calogValueNil(result);
status = calogAggCreate(&user, calogMapE);
if (status != calogOkE) {
return calogFail(result, status, "makeUser could not allocate");
}
calogValueString(&key, "name", 4);
calogValueString(&val, "ada", 3);
calogAggSet(user, &key, &val);
calogValueString(&key, "age", 3);
calogValueInt(&val, 36);
calogAggSet(user, &key, &val);
calogValueAgg(result, user);
return calogOkE;
}
static int32_t nativeMapAge(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData) {
CalogValueT key;
CalogValueT *found;
(void)userData;
calogValueNil(result);
if (argCount != 1 || args[0].type != calogAggE) {
return calogFail(result, calogErrArgE, "mapAge expects a map");
}
// Read a field out of a map the script built and handed to C (aggregate ingress).
calogValueString(&key, "age", 3);
found = calogAggGet(args[0].as.agg, &key);
calogValueFree(&key);
if (found != NULL && found->type == calogIntE) {
atomic_store(&reportedValue, found->as.i);
}
return calogOkE;
}
static int32_t nativeReport(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData) {
(void)userData;
calogValueNil(result);
if (argCount != 1 || args[0].type != calogIntE) {
return calogFail(result, calogErrArgE, "report expects one integer");
}
atomic_store(&reportedCtxId, calogCurrentId());
atomic_store(&reportedValue, args[0].as.i);
return calogOkE;
}
static int32_t nativeReportInline(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData) {
(void)args;
(void)argCount;
(void)userData;
atomic_store(&inlineCtxId, calogCurrentId());
calogValueNil(result);
return calogOkE;
}
static int32_t nativeReportName(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData) {
size_t length;
(void)userData;
calogValueNil(result);
if (argCount != 1 || args[0].type != calogStringE) {
return calogFail(result, calogErrArgE, "reportName expects one string");
}
length = (size_t)args[0].as.s.length;
if (length >= sizeof(storedName)) {
length = sizeof(storedName) - 1;
}
memcpy(storedName, args[0].as.s.bytes, length);
storedName[length] = '\0';
atomic_store(&nameLen, (int32_t)length);
return calogOkE;
}
static int32_t nativeSetCb(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData) {
(void)userData;
calogValueNil(result);
if (argCount != 1 || args[0].type != calogFnE) {
return calogFail(result, calogErrArgE, "setCb expects one function");
}
calogFnRetain(args[0].as.fn);
atomic_store(&storedCb, args[0].as.fn);
return calogOkE;
}
static void onError(uint64_t contextId, const char *message, void *userData) {
(void)message;
(void)userData;
atomic_store(&errorCtxId, contextId);
atomic_fetch_add(&errorCount, 1);
}
static void pumpUntilDone(void) {
struct timespec ts = { 0, 500000 };
int errorsBefore;
int i;
errorsBefore = atomic_load(&errorCount);
for (i = 0; i < PUMP_LIMIT; i++) {
calogPump(calog);
if (atomic_load(&scriptDone) || atomic_load(&errorCount) != errorsBefore) {
calogPump(calog);
return;
}
nanosleep(&ts, NULL);
}
}
static void testHostAndInlineNatives(void) {
CalogContextT *ctx;
ctx = calogContextOpen(calog, &calogMrubyEngine);
CHECK(ctx != NULL, "opened an mruby context");
atomic_store(&scriptDone, false);
calogContextEval(ctx, "report(42)\nreportInline(1)\ndone()");
pumpUntilDone();
CHECK(atomic_load(&reportedValue) == 42, "host native received the argument");
CHECK(atomic_load(&reportedCtxId) == 0, "default native ran on the host thread (id 0)");
CHECK(atomic_load(&inlineCtxId) == calogContextId(ctx), "inline native ran on the script's own thread");
calogContextClose(ctx);
}
static void testMaterializedRecord(void) {
CalogContextT *ctx;
ctx = calogContextOpen(calog, &calogMrubyEngine);
atomic_store(&scriptDone, false);
atomic_store(&nameLen, -1);
atomic_store(&reportedValue, 0);
calogContextEval(ctx, "u = makeUser()\nreport(u['age'])\nreportName(u['name'])\ndone()");
pumpUntilDone();
CHECK(atomic_load(&reportedValue) == 36, "read an int field from a materialized record hash");
CHECK(atomic_load(&nameLen) == 3 && memcmp(storedName, "ada", 3) == 0, "read a string field from a materialized record hash");
calogContextClose(ctx);
}
static void testMapIngress(void) {
CalogContextT *ctx;
ctx = calogContextOpen(calog, &calogMrubyEngine);
atomic_store(&scriptDone, false);
atomic_store(&reportedValue, 0);
// The script builds a hash (with a nested array, exercising list ingress too) with STRING
// keys (=> not : which would make symbols) and hands it to a native, which reads a field.
calogContextEval(ctx, "m = {'age' => 9, 'tags' => [1, 2]}\nmapAge(m)\ndone()");
pumpUntilDone();
CHECK(atomic_load(&reportedValue) == 9, "native read a field from a hash the script built");
calogContextClose(ctx);
}
static void testForeignFunction(void) {
CalogContextT *ctx;
ctx = calogContextOpen(calog, &calogMrubyEngine);
atomic_store(&scriptDone, false);
atomic_store(&reportedValue, 0);
// The script receives a host-owned function value (a real Ruby Proc) and calls it.
calogContextEval(ctx, "adder = getAdder()\nreport(adder.call(2, 3))\ndone()");
pumpUntilDone();
CHECK(atomic_load(&reportedValue) == 5, "script called a foreign function value pushed in from the host");
calogContextClose(ctx);
}
static void testCrossThreadCallback(void) {
CalogContextT *ctx;
CalogFnT *callback;
CalogValueT arg;
CalogValueT result;
int32_t status;
ctx = calogContextOpen(calog, &calogMrubyEngine);
atomic_store(&scriptDone, false);
atomic_store(&storedCb, NULL);
calogContextEval(ctx, "cb = ->(x) { x + 100 }\nsetCb(cb)\ndone()");
pumpUntilDone();
callback = atomic_load(&storedCb);
CHECK(callback != NULL, "a Ruby lambda was captured as a CalogFnT");
calogValueInt(&arg, 7);
status = calogFnInvoke(callback, &arg, 1, &result);
CHECK(status == calogOkE && result.type == calogIntE && result.as.i == 107, "cross-thread callable invoke routed to the owner");
calogValueFree(&result);
calogValueFree(&arg);
calogFnRelease(callback);
calogContextClose(ctx);
}
static void testScriptError(void) {
CalogContextT *ctx;
int32_t before;
ctx = calogContextOpen(calog, &calogMrubyEngine);
before = atomic_load(&errorCount);
atomic_store(&scriptDone, false);
calogContextEval(ctx, "raise 'intentional test error'");
pumpUntilDone();
CHECK(atomic_load(&errorCount) == before + 1, "a fire-and-forget script error reached the error handler");
CHECK(atomic_load(&errorCtxId) == calogContextId(ctx), "the error names the failing context");
calogContextClose(ctx);
}
static void testConcurrentContexts(void) {
CalogContextT *ctxs[3];
struct timespec ts = { 0, 500000 };
int32_t i;
atomic_store(&bumpCount, 0);
for (i = 0; i < 3; i++) {
ctxs[i] = calogContextOpen(calog, &calogMrubyEngine);
calogContextEval(ctxs[i], "bump()\nbump()\nbump()");
}
for (i = 0; i < PUMP_LIMIT && atomic_load(&bumpCount) < 9; i++) {
calogPump(calog);
nanosleep(&ts, NULL);
}
CHECK(atomic_load(&bumpCount) == 9, "three concurrent mruby contexts all dispatched to the host thread");
for (i = 0; i < 3; i++) {
calogContextClose(ctxs[i]);
}
}
int main(void) {
calog = calogCreate();
if (calog == NULL) {
printf("calog create failed\n");
return 1;
}
calogSetErrorHandler(calog, onError, NULL);
calogRegister(calog, "report", nativeReport, NULL);
calogRegister(calog, "setCb", nativeSetCb, NULL);
calogRegister(calog, "done", nativeDone, NULL);
calogRegister(calog, "bump", nativeBump, NULL);
calogRegister(calog, "makeUser", nativeMakeUser, NULL);
calogRegister(calog, "reportName", nativeReportName, NULL);
calogRegister(calog, "getAdder", nativeGetAdder, NULL);
calogRegister(calog, "mapAge", nativeMapAge, NULL);
calogRegisterInline(calog, "reportInline", nativeReportInline, NULL);
testHostAndInlineNatives();
testMaterializedRecord();
testMapIngress();
testForeignFunction();
testCrossThreadCallback();
testScriptError();
testConcurrentContexts();
calogDestroy(calog);
printf("\n%d checks, %d failed\n", testsRun, testsFailed);
fflush(stdout);
if (testsFailed != 0) {
return 1;
}
return 0;
}

3
vendor/mruby/.codespellrc vendored Normal file
View file

@ -0,0 +1,3 @@
[codespell]
ignore-words = .github/linters/codespell.txt
skip = ./build,./doc/api,./doc/capi

14
vendor/mruby/.dockerignore vendored Normal file
View file

@ -0,0 +1,14 @@
.DS_Store
.idea
.vscode
.yardoc
*.bak
*.iml
*.ipr
*.swp
*.tmp
bin
build
doc/api
doc/capi
node_modules

30
vendor/mruby/.editorconfig vendored Normal file
View file

@ -0,0 +1,30 @@
# About this file, see:
# Website: https://editorconfig.org/
# For Emacs users: https://github.com/editorconfig/editorconfig-emacs
# For Vim users: https://github.com/editorconfig/editorconfig-vim
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
tab_width = 8
trim_trailing_whitespace = true
[{Makefile,Makefile.*,makefile,*.mk}]
indent_style = tab
#max_line_length = 80
#[*.{c,cc,C,cxx,cpp,h,hh,H,hxx,hpp,inc,y}]
#max_line_length = 120
#[{*.rb,Rakefile,rakefile,*.rake,*.gemspec,*.gembox}]
#max_line_length = 120
# limitation to US-ASCII
[*.bat]
end_of_line = crlf
#max_line_length = 80

130
vendor/mruby/.pre-commit-config.yaml vendored Normal file
View file

@ -0,0 +1,130 @@
---
# https://github.com/j178/prek
default_stages: [pre-commit, pre-push]
default_language_version:
python: python3
node: 24.14.0
minimum_pre_commit_version: "3.2.0"
exclude: "^tools/lrama/"
repos:
- repo: meta
hooks:
- id: identity
name: run identity
description: check your identity
- id: check-hooks-apply
name: run check-hooks-apply
description: check hooks apply to the repository
- repo: local
hooks:
- id: prettier
name: run prettier
description: format files with prettier
entry: prettier --write '**/*.md' '**/*.yaml' '**/*.yml'
files: \.(md|ya?ml)$
language: node
additional_dependencies: ["prettier@3.7.4"]
pass_filenames: false
stages: [manual]
- id: check-zip-file-is-not-committed
name: disallow zip files
description: Zip files are not allowed in the repository
language: fail
entry: |
Zip files are not allowed in the repository as they are hard to
track and have security implications. Please remove the zip file from the repository.
files: \.zip$
- repo: https://github.com/gitleaks/gitleaks
rev: v8.30.1
hooks:
- id: gitleaks
name: run gitleaks
description: detect hardcoded secrets with gitleaks
- repo: https://github.com/oxipng/oxipng
rev: v10.1.0
hooks:
- id: oxipng
name: run oxipng
description: use lossless compression to optimize PNG files
args: ["--fix", "-o", "4", "--strip", "safe", "--alpha"]
stages: [manual]
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: check-added-large-files
- id: check-case-conflict
- id: check-executables-have-shebangs
exclude: ^test/t/lang\.rb$
- id: check-illegal-windows-names
- id: check-merge-conflict
- id: check-shebang-scripts-are-executable
- id: check-vcs-permalinks
- id: check-yaml
- id: destroyed-symlinks
- id: detect-aws-credentials
args: [--allow-missing-credentials]
- id: detect-private-key
- id: end-of-file-fixer
- id: file-contents-sorter
args: [--unique]
files: ^\.github/linters/codespell\.txt$
- id: fix-byte-order-marker
- id: forbid-submodules
- id: mixed-line-ending
- id: trailing-whitespace
- repo: https://github.com/Lucas-C/pre-commit-hooks
rev: v1.5.6
hooks:
- id: forbid-tabs
name: run no-tabs checker
description: check the codebase for tabs
exclude: Makefile$
- id: remove-tabs
name: run tabs remover
description: find and convert tabs to spaces
args: [--whitespaces-count, "2"]
exclude: Makefile$
- repo: https://github.com/rhysd/actionlint
rev: v1.7.12
hooks:
- id: actionlint
name: run actionlint
description: lint GitHub Actions workflow files
- repo: https://github.com/codespell-project/codespell
rev: v2.4.2
hooks:
- id: codespell
name: run codespell
description: check spelling with codespell
- repo: https://github.com/igorshubovych/markdownlint-cli
rev: v0.48.0
hooks:
- id: markdownlint
name: run markdownlint
description: checks the style of Markdown files
args: [--config=.github/linters/.markdown-lint.yml]
types: [markdown]
files: \.md$
- repo: https://github.com/rubocop/rubocop
rev: v1.86.0
hooks:
- id: rubocop
name: run rubocop
description: RuboCop is a Ruby code style checker (linter) and formatter based on the community-driven Ruby Style Guide
exclude: ^test/t/syntax\.rb$
args: [--config=.github/linters/.rubocop.yml]
- repo: https://github.com/shellcheck-py/shellcheck-py
rev: v0.11.0.1
hooks:
- id: shellcheck
name: run shellcheck
description: check shell scripts with a static analysis tool
- repo: https://github.com/adrienverge/yamllint
rev: v1.38.0
hooks:
- id: yamllint
name: run yamllint
description: check YAML files with yamllint
args: [--strict, -c=.github/linters/.yaml-lint.yml]
types: [yaml]
files: \.ya?ml$

6
vendor/mruby/.prettierignore vendored Normal file
View file

@ -0,0 +1,6 @@
# Ignore artifacts:
build
coverage
doc/internal/opcode.md
tools/lrama
.venv

3
vendor/mruby/.prettierrc vendored Normal file
View file

@ -0,0 +1,3 @@
{
"bracketSpacing": false
}

11
vendor/mruby/.travis.yml vendored Normal file
View file

@ -0,0 +1,11 @@
language: c
jobs:
- os: linux
- os: osx
env:
- MRUBY_CONFIG=ci/gcc-clang
script:
- rake -m test:run:serial

23
vendor/mruby/.yardopts vendored Normal file
View file

@ -0,0 +1,23 @@
--markup markdown
--plugin mruby
--plugin coderay
--output-dir doc/api
src/**/*.c
mrblib/**/*.rb
include/**/*.h
mrbgems/*/src/**/*.c
mrbgems/*/mrblib/**/*.rb
mrbgems/*/include/**/*.h
-
CONTRIBUTING.md
SECURITY.md
TODO.md
doc/*.md
doc/guides/*.md
doc/internal/*.md
AUTHORS
LEGAL
LICENSE
NEWS

348
vendor/mruby/AUTHORS vendored Normal file
View file

@ -0,0 +1,348 @@
# Authors of mruby (mruby developers)
## The List of Contributors sorted by number of commits (as of 2026-03-02 02877f0)
7532 Yukihiro "Matz" Matsumoto (@matz)*
712 dearblue (@dearblue)*
587 KOBAYASHI Shuji (@shuujii)
353 Daniel Bovensiepen (@bovi)*
345 Takeshi Watanabe (@take-cheeze)*
333 Masaki Muranaka (@monaka)
255 John Bampton (@jbampton)
234 Jun Hiroe (@suzukaze)
228 Tomoyuki Sahara (@tsahara)*
220 Cremno (@cremno)*
209 Yuki Kurihara (@ksss)+
144 Yasuhiro Matsumoto (@mattn)*
113 Carson McDonald (@carsonmcdonald)
104 Tomasz Pędraszewski (@dabroz)*
83 Akira Yumiyama (@akiray03)*
83 skandhas (@skandhas)
80 Masamitsu MURASE (@masamitsu-murase)
73 Hiroshi Mimaki (@mimaki)*
71 Tatsuhiko Kubo (@cubicdaiya)*
71 Yuichiro MASUI (@masuidrive)
62 Yuichiro Kaneko (@yui-knk)+
59 Kurebayashi, Takahiro (@crimsonwoods)*
56 h2so5 (@h2so5)
52 Ralph Desir (@Mav7)*
48 Paolo Bosetti (@pbosetti)*
45 Rory O'Connell (@RoryO)*
42 fleuria (@flaneur2020)
40 Christopher Aue (@christopheraue)
40 Seba Gamboa (@sagmor)
39 Kouhei Sutou (@kou)*
38 Koji Yoshioka (@kyab)*+
32 Masayoshi Takahashi (@takahashim)+
31 MATSUMOTO Ryosuke (@matsumotory)*
30 Nobuyoshi Nakada (@nobu)
26 Hoshiumi Arata (@hoshiumiarata)*
25 Julian Aron Prenner (@furunkel)*
22 Clayton Smith (@clayton-shopify)
22 Uchio Kondo (@udzura)*
22 Zachary Scott (@zzak)*
21 Ryan Lopopolo (@lopopolo)
20 Ryan Scott (@ryan-scott-dev)*
20 google-labs-jules[bot] (@google-jules)
19 Bouke van der Bijl (@bouk)
19 Jared Breeden (@jbreeden)*
19 go kikuta (@gkta)*
18 Corey Powell (@IceDragon200)
18 Hidetaka Takano (@TJ-Hidetaka-Takano)
18 Jon Maken (@jonforums)+
18 leviongit (@leviongit)
18 mirichi (@mirichi)
17 Mitchell Blank Jr (@mitchblank)*
16 HASUMI Hitoshi (@hasumikin)
16 bggd (@bggd)
16 kano4 (@kano4)
15 Felix Jones (@felixjones)*
14 Blaž Hrastnik (@archseer)*
14 Kazuki Tsujimoto (@k-tsj)
14 Tadashi FUKUZAWA (@FUKUZAWA-Tadashi)+
14 fn ⌃ ⌥ (@FnControlOption)
13 Jose Narvaez (@goyox86)
13 Patrick Hogan (@pbhogan)
12 Akira Kuroda (@akuroda)
12 Kouki Ooyatsu (kaishuu0123)*
12 NAKAMURA Usaku (@unak)*
12 Ray Chason (@chasonr)*
12 SiZiOUS (@suzious)
12 Takashi Sawanaka (@sdottaka)*
12 Ukrainskiy Sergey (@ukrainskiysergey)
12 Xuejie "Rafael" Xiao (@xxuejie)*
11 Julien Ammous (@schmurfy)
11 Kazuho Oku (@kazuho)
11 RIZAL Reckordp (@Reckordp)+
11 Seeker (@SeekingMeaning)
11 takkaw (@takkaw)
10 Hendrik (@Asmod4n)
10 Miura Hideki (@miura1729)
10 Narihiro Nakamura (@authorNari)
10 YAMAMOTO Masaya (pandax381)
10 Yuichi Nishiwaki (@nyuichi)
9 Akira Mitsui (@murasesyuka)*
9 Frank Celler (@fceller)
9 Tatsuya Matsumoto (@tmash06)*
8 Takashi Sogabe (@sogabe)
8 Wataru Ashihara (@wataash)*
7 Bhargava Shastry (@bshastry)*
7 Kouichi Nakanishi (@keizo042)
7 Rubyist (@expeditiousRubyist)
7 Simon Génier (@simon-shopify)
7 Terence Lee (@hone)
7 roco (@rystyle)*
7 vickash (@vickash)
6 Akito Mochizuki (@ak-mochi)
6 Beoran (@beoran)
6 David Siaw (@davidsiaw)*
6 Frederick John Milens III (@fjmilens3)
6 Hiro Asari (@BanzaiMan)
6 INOUE Yasuyuki (@yasuyuki)
6 Junji Sawada (@junjis0203)
6 Kenji Okimoto (@okkez)+
6 Paweł Świątkowski (@katafrakt)
6 Selman ULUG (@selman)
6 Yusuke Endoh (@mame)*
6 buty4649 (@buty4649)
6 masahino (@masahino)
5 Chris Reuter (@suetanvil)
5 Davide D'Agostino (@DAddYE)
5 Eric Hodel (@drbrain)
5 Ichito Nagata (@i110)
5 Keita Obo (@ktaobo)*
5 Max Anselm (@silverhammermba)
5 Rodrigo Malizia (@rmalizia44)+
5 Ryan Davis (@zenspider)
5 Syohei YOSHIDA (@syohex)
5 TOMITA Masahiro (@tmtm)
5 Yurie Yamane (@yurie)+
5 dreamedge (@dreamedge)
5 nkshigeru (@nkshigeru)
5 xuejianqing (@joans321)
4 Chris Hasiński (@khasinski)
4 Dante Catalfamo (@dantecatalfamo)
4 Goro Kikuchi (@gorogit)
4 Herwin Weststrate (@herwinw)
4 Horimoto Yasuhiro (@komainu8)
4 Jon Moss (@maclover7)
4 Ken Muramatsu (@ken-mu)+
4 Kohei Suzuki (@eagletmt)
4 Lanza (@LanzaSchneider)
4 Li Yazhou (@flaneur2020)
4 Marcus Stollsteimer (@stomar)
4 Mark Delk (@jethrodaniel)
4 NARUSE, Yui (@nurse)
4 Ravil Bayramgalin (@brainopia)*+
4 Satoshi Odawara (@SatoshiOdawara)
4 UENO, M. (@eunos-1128)
4 Yuhei Okazaki (@Yuuhei-Okazaki)*
4 Yuji Yamano (@yyamano)
4 kurodash (@kurodash)*
4 wanabe (@wanabe)*
3 Anton Davydov (@davydovanton)
3 Aurora Nockert (@auroranockert)
3 Carlo Prelz (@asfluido)*
3 Daniel K. Sierpiński (@513ry)+
3 David Turnbull (@AE9RB)
3 Franck Verrot (@franckverrot)
3 Hirohito Higashi (@HirohitoHigashi)
3 J. Mutua (@katmutua)+
3 Jan Berdajs (@mrbrdo)
3 Jonas Minnberg (@sasq64)
3 Joseph McCullough (@joequery)
3 Mark McCurry (@fundamental)
3 Meder Kydyraliev (@meder)
3 Nobuhiro Iwamatsu (@iwamatsu)
3 Per Lundberg (@perlun)*
3 Rob Fors (@robfors)*
3 Robert Rowe (@CaptainJet)
3 Sebastián Katzer (@katzer)*
3 Shuta Kimura (@kimushu)+
3 TERAJIMA, Motoyuki (@trmmy)
3 Taichi AOKI (@aoki1980taichi)
3 Takashi Kokubun (@k0kubun)
3 Tatsuhiro Tsujikawa (@tatsuhiro-t)
3 Thiago Scalone (@scalone)
3 Vladimir Dementyev (@palkan)*
3 William Light (@wrl)
3 bamchoh (@bamchoh)
3 sasaki takeru (@takeru)
3 windwiny (@windwiny)
2 Akira Moroo (@retrage)
2 Artur K (@nemerle)
2 Christian Mauceri (@mauceri)
2 Craig Lehmann (@craiglrock)*
2 Dominic Sisneros (@dsisnero)*
2 Dusan D. Majkic (@dmajkic)
2 Emiliano Lesende (@3miliano)
2 Francois Chagnon (@EiNSTeiN-)*
2 Gilad Zohari (@gzohari)
2 Go Saito (@govm)
2 Hiroyuki Iwatsuki (@iwadon)
2 Huei-Horng Yo (@hiroshiyui)
2 Jonas Kulla (@Ancurio)
2 Jun Takeda (@takjn)
2 Kazuaki Tanaka (@kaz0505)
2 Kazuhiko Yamashita (@pyama86)+
2 Kazuhiro Sera (@seratch)
2 Kuroda Daisuke (@dycoon)+
2 Lothar Scholz (@llothar)
2 Lukas Joeressen (@kext)
2 Masahiro Wakame (@vvkame)+
2 Minao Yamamoto (@tarosay)+
2 Nihad Abbasov (@NARKOZ)
2 Robert Mosolgo (@rmosolgo)
2 Russel Hunter Yukawa (@rhykw)+
2 Ryunosuke SATO (@tricknotes)
2 Santa Zhang (@santazhang)
2 Serg Podtynnyi (@shtirlic)
2 Shannen Saez (@shancat)
2 Shouji Kuboyama (@Shokuji)*
2 SouthWolf (@southwolf)
2 TJ Singleton (@tjsingleton)
2 Taiyo Mizuhashi (@taiyoslime)+
2 Tomás Pollak (@tomas)*
2 Yutaka HARA (@yhara)*+
2 Zhang Xiaohui (@hifoolno)
2 icm7216 (@icm7216)
1 A-Sat (@asatou)+
1 AN Long (@aisk)
1 Abinoam Praxedes Marques Junior (@abinoam)
1 Alex Wang (@nanamiwang)+
1 AlexDenisov (@AlexDenisov)
1 Andrew Nordman (@cadwallion)
1 Ashish Kurmi (@boahc077)
1 Atsushi Morimoto (@mynz)
1 Ben A Morgan (@BenMorganIO)
1 Benoit Daloze (@eregon)
1 Bradley Whited (@esotericpig)
1 Colin MacKenzie IV (@sinisterchipmunk)
1 Daehyub Kim (@lateau)
1 Daniel Varga (@vargad)
1 Diamond Rivero (@diamant3)
1 Edgar Boda-Majer (@eboda)
1 Fangrui Song (@MaskRay)
1 Flavio Medeiros (@flaviommedeiros)
1 Francis Bogsanyi (@fbogsany)
1 Guo Xiao (@guoxiao)
1 Gwen Boatrite (@boatrit)
1 Gwendolyn Boatrite (@boatrite)
1 HARADA Makoto (@haramako)
1 HAYASHI Kentaro (@kenhys)
1 Hiroki Mori (@yamori813)+
1 Hiromasa Ishii (@Hir0)+
1 Hiroyuki Matsuzaki (@Hiroyuki-Matsuzaki)
1 Hugo Logmans (@hlogmans)
1 Jack Danger Canty (@JackDanger)
1 Jeff Federman (@jefffederman)
1 Jeffrey Crowell (@crowell)
1 Jeremy Ong (@jeremyong)
1 Jiro Nishiguchi (@spiritloose)
1 Joachim Baran (@indiedotkim)
1 Joe Kutner (@jkutner)
1 Jun Aruga (@junaruga)
1 Junichi Kajiwara (@kjunichi)
1 Jurriaan Pruis (@jurriaan)
1 Katsuhiko Kageyama (@kishima)+
1 Katsuyoshi Ito (@katsuyoshi)
1 Kazuhiro NISHIYAMA (@znz)
1 Kei Sawada (@remore)
1 Kim H Madsen (@kimhmadsen)
1 Koichi ITO (@koic)
1 Konstantin Haase (@rkh)
1 Leo Neat (@Leo-Neat)
1 Lian Cheng (@liancheng)
1 Luis Lavena (@luislavena)
1 Lukas Elmer (@lukaselmer)
1 Lukas Stabe (@Ahti)
1 M.Naruoka (@fenrir-naru)
1 Marcelo Juchem (@juchem)
1 Martin Bosslet (@emboss)+
1 Masahiko Sawada (@MasahikoSawada)
1 Matt Aimonetti (@mattetti)
1 Max Base (@MaxFork)
1 Maxim Abramchuk (@MaximAbramchuck)
1 Megumi Tomita (@tomykaira)+
1 Mitchell Hashimoto (@mitchellh)
1 Mitsutaka Mimura (@takkanm)
1 Nathan Ladd (@ntl)
1 Nicholas (@knf)
1 Nozomi SATO (@nozomiS)
1 Okumura Takahiro (@hfm)
1 Oliver Chang (@oliverchang)
1 Patrick Ellis (@pje)
1 Patrick Pokatilo (@SHyx0rmZ)
1 Pavel Evstigneev (@Paxa)+
1 Pete Kinnecom (@petekinnecom)
1 Piotr Usewicz (@pusewicz)
1 Prayag Verma (@pra85)
1 Ranmocy (@ranmocy)
1 Robert McNally (@wolfmcnally)
1 Ryan Scott Lewis (@RyanScottLewis)
1 Ryo Okubo (@syucream)
1 SAkira a.k.a. Akira Suzuki (@sakisakira)
1 Santiago Rodriguez (@sanrodari)
1 Satoh, Hiroh (@cho45)+
1 Satoru Naba (@snaba)+
1 Sayed Abdelhaleem (@visualsayed)
1 Sergey Ukrainskiy (@ukrainskiysergey)
1 Shugo Maeda (@shugo)
1 Sinkevich Artem (@ArtSin)
1 Sorah Fukumori (@sorah)
1 Stephen Jothen (@sjothen)
1 Stuart Hinson (@stuarth)
1 Takuma Kume (@takumakume)+
1 Takuya ASADA (@syuu1228)
1 Thomas Schmidt (@digitaltom)
1 Timo Schilling (@timoschilling)
1 Tom Black (@blacktm)
1 Utkarsh Kukreti (@utkarshkukreti)
1 W (@graywolf)
1 Wuffers Lightwolf (@w-x-l)
1 YAMAMOTO Yuji (@igrep)
1 Yevhen Viktorov (@yevgenko)
1 Yoji SHIDARA (@darashi)
1 Yoshiori SHOJI (@yoshiori)
1 Yuji Yokoo (@yujiyokoo)
1 Yukang (@chenyukang)
1 Yurii Nakonechnyi (@inobelar)
1 Yusuke Suzuki (@Constellation)+
1 Yusuke Tanaka (@csouls)
1 alpha.netzilla (@alpha-netzilla)
1 arton (@arton)
1 duangsuse (@duangsuse)
1 fl0l0u (@fl0l0u)
1 hasse (@hasse09052)
1 hhc0null (@hhc0null)
1 iTitou (@titouanc)
1 javier ramírez (@javier)
1 liyuray (@liyuray)
1 lucas dicioccio (@lucasdicioccio)
1 n4o847 (@n4o847)
1 niyarin (@niyarin)
1 robert (@R-obert)
1 sbsoftware (@sbsoftware)
1 ssmallkirby (@smallkirby)
1 taku toyama (@tsuichu)
`*` - Entries unified according to names and addresses
`+` - Entries with names different from commits
## Contributors without named commits
Yuichi Osawa (Mitsubishi Electric Micro-Computer Application Software)
Shota Nakano (Manycolors)
Bjorn De Meyer
## Corporate contributors
Ministry of Economy, Trade and Industry, Japan
Kyushu Bureau of Economy, Trade and Industry
SCSK KYUSHU CORPORATION
Kyushu Institute of Technology
Network Applied Communication Laboratory, Inc.
Internet Initiative Japan Inc.
Specified non-profit organization mruby Forum
Mitsubishi Electric Micro-Computer Application Software Co.,Ltd.
Manycolors, Inc.

193
vendor/mruby/CONTRIBUTING.md vendored Normal file
View file

@ -0,0 +1,193 @@
# How to contribute
mruby is an open-source project which is looking forward to each contribution.
Contributors agree to license their contribution(s) under MIT license.
## Your Pull Request
To make it easy to review and understand your change please keep the following
things in mind before submitting your pull request:
- Work on the latest possible state of **mruby/master**
- Create a branch which is dedicated to your change
- Test your changes before creating a pull request (`rake test`)
- If possible write a test case which confirms your change
- Don't mix several features or bugfixes in one pull request
- Create a meaningful commit message
- Explain your change (i.e. with a link to the issue you are fixing)
- Use mrbgem to provide non ISO features (classes, modules and methods) unless
you have a special reason to implement them in the core
## Security Issues
If you discover a security vulnerability:
- **High priority security vulnerabilities** (RCE): Report via email to <matz@ruby.or.jp>
- **VM crashes from valid Ruby code**: Please report as regular bug reports on our issue tracker
For detailed guidance on what qualifies as a security issue and what doesn't, see [SECURITY.md](SECURITY.md).
## prek
We use [prek](https://github.com/j178/prek), a fast Rust-based pre-commit hook manager.
It reads the standard `.pre-commit-config.yaml` format.
Install `prek` following the [installation guide](https://github.com/j178/prek#installation),
then install the hooks with `prek install`.
Now `prek` will run automatically on git commit!
It's usually a good idea to run the hooks against all the files when adding new hooks (usually `prek`
will only run on the changed files during git hooks). Use `prek run --all-files` to check all files.
To run a single hook use `prek run --all-files <hook_id>`
To update use `prek autoupdate`
Sometimes you might need to skip one or more hooks which can be done with the `SKIP` environment variable.
`$ SKIP=yamllint git commit -m "foo"`
For convenience, we have added `prek run --all-files`, `prek install` and `prek autoupdate`
to both the Makefile and the Rakefile. Run them with:
- `make check` or `rake check`
- `make checkinstall` or `rake checkinstall`
- `make checkupdate` or `rake checkupdate`
To configure hooks you can modify the config file [.pre-commit-config.yaml](.pre-commit-config.yaml).
We use [GitHub Actions](.github/workflows/pre-commit.yml) to run `prek` on every pull request.
### prek quick links
- [prek GitHub](https://github.com/j178/prek)
- [Installation](https://github.com/j178/prek#installation)
- [Usage](https://github.com/j178/prek#usage)
## Docker
We have both a `Dockerfile` and `docker-compose.yml` files in the repository root.
You can run these with the command line or use
[Docker Desktop](https://www.docker.com/products/docker-desktop/).
The Docker image is running Debian bullseye with Ruby and Python installed.
You can build the Docker image with:
`$ docker-compose build test`
So far we just have one service: `test`. Running the default `docker-compose`
command will create the Docker image, spin up a container and then build and
run all mruby tests.
The default `docker-compose` command is:
`$ docker-compose -p mruby run test`
You can also use Make or Rake to run the default `docker-compose`
command from above:
- `make composetest`
- `rake composetest`
List your Docker images with:
```console
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mruby-test latest ec60f9536948 29 seconds ago 1.29GB
```
You can also run any custom `docker-compose` command which will override
the default. For example to run `prek run --all-files` type:
`$ docker-compose -p mruby run test prek run --all-files`
For convenience, you can also run `prek` with:
- `make composecheck`
- `rake composecheck`
The bonus of running `prek` with `docker-compose` is that you won't need
to install `prek` and the hooks on your local machine.
Note limitation: currently running `prek` with `docker-compose` we
skip the `check-executables-have-shebangs` hook.
Two more examples of custom `docker-compose` commands are:
- `$ docker-compose -p mruby run test ls`
- `$ docker-compose -p mruby run test rake doc:api`
If you want to test using a different `docker-compose` YAML config file you
can use the `-f` flag:
`$ docker-compose -p mruby -f docker-compose.test.yml run test`
- <https://docs.docker.com/compose/>
- <https://docs.docker.com/engine/reference/commandline/cli/>
## Spell Checking
We are using `prek` to run [codespell](https://github.com/codespell-project/codespell)
to check code for common misspellings. We have a small custom dictionary file [codespell.txt](.github/linters/codespell.txt).
## Coding conventions
How to style your C and Ruby code which you want to submit.
### C code
The core part (parser, bytecode-interpreter, core-lib, etc.) of mruby is
written in the C programming language. Please note the following hints for your
C code:
#### Comply with C99 (ISO/IEC 9899:1999)
mruby should be highly portable to other systems and compilers. For this it is
recommended to keep your code as close as possible to the C99 standard
(<http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf>).
Visual C++ is also an important target for mruby (supported version is 2013 or
later). For this reason features that are not supported by Visual C++ may not
be used (e.g. `%z` of `strftime()`).
NOTE: Old GCC requires `-std=gnu99` option to enable C99 support.
#### Reduce library dependencies to a minimum
The dependencies to libraries should be kept to an absolute minimum. This
increases the portability but makes it also easier to cut away parts of mruby
on-demand.
#### Insert a break after the function return value:
```c
int
main(void)
{
...
}
```
### Ruby code
Parts of the standard library of mruby are written in the Ruby programming
language itself. Please note the following hints for your Ruby code:
#### Comply with the Ruby standard (ISO/IEC 30170:2012)
mruby is currently targeting to execute Ruby code which complies to ISO/IEC
30170:2012 (<https://www.iso.org/standard/59579.html>),
unless there's a clear reason, e.g. the latest Ruby has changed behavior from ISO.
## Building documentation
### mruby API
- [YARD](https://yardoc.org/) - YARD is a documentation generation tool for the Ruby programming language
- [yard-mruby](https://rubygems.org/gems/yard-mruby) - Document mruby sources with YARD
- [yard-coderay](https://rubygems.org/gems/yard-coderay) - Adds coderay syntax highlighting to YARD docs
### C API
- [Doxygen](https://www.doxygen.nl/) - Generate documentation from source code
- [Graphviz](https://graphviz.org/) - Graphviz is open source graph visualization software

13
vendor/mruby/Dockerfile vendored Normal file
View file

@ -0,0 +1,13 @@
FROM ruby:3.2.2-bullseye
RUN apt-get update && apt-get install --no-install-recommends -y python3-pip shellcheck \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY Gemfile Gemfile.lock .pre-commit-config.yaml ./
RUN bundle install && pip3 install --no-cache-dir pre-commit && git init . && pre-commit install-hooks
COPY . .

2748
vendor/mruby/Doxyfile vendored Normal file

File diff suppressed because it is too large Load diff

8
vendor/mruby/Gemfile vendored Normal file
View file

@ -0,0 +1,8 @@
# frozen_string_literal: true
source 'https://rubygems.org'
gem 'rake'
gem 'yard'
gem 'yard-coderay'
gem 'yard-mruby'

25
vendor/mruby/Gemfile.lock vendored Normal file
View file

@ -0,0 +1,25 @@
GEM
remote: https://rubygems.org/
specs:
coderay (1.1.3)
rake (13.3.1)
yard (0.9.38)
yard-coderay (0.1.0)
coderay
yard
yard-mruby (0.3.0)
yard (~> 0.9.0)
PLATFORMS
ruby
x86_64-darwin-21
x86_64-linux
DEPENDENCIES
rake
yard
yard-coderay
yard-mruby
BUNDLED WITH
2.4.10

62
vendor/mruby/LEGAL vendored Normal file
View file

@ -0,0 +1,62 @@
LEGAL NOTICE INFORMATION
------------------------
All the files in this distribution are covered under the MIT license
(see the file LICENSE) except some files mentioned below:
- src/string.c (memsearch_swar): 2 clause BSD license code by Wojciech Muła (@WojciechMula)
- src/fmt_fp.c: public domain by Dave Hylands (@dhylands)
- mrbgems/mruby-dir/src/Win/dirent.c: MIT-like license by Kevlin Henney
[src/string.c]
The implementation of mrb_memsearch_ss() is taken from
https://github.com/WojciechMula/sse4-strstr.git
Copyright (c) 2008-2016, Wojciech Muła
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. 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.
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
HOLDER 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.
[src/fmt_fp.c]
The code in this function was inspired from Fred Bayer's pdouble.c.
Since pdouble.c was released as Public Domain, I'm releasing this
code as public domain as well.
Dave Hylands
The original code can be found in https://github.com/dhylands/format-float
[mrbgems/mruby-dir/src/Win/dirent.c] used only for Windows platform
Copyright Kevlin Henney, 1997, 2003, 2012. All rights reserved.
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose is hereby granted without fee, provided
that this copyright and permissions notice appear in all copies and
derivatives.
This software is supplied "as is" without express or implied warranty.
But that said, if there are any problems please get in touch.

19
vendor/mruby/LICENSE vendored Normal file
View file

@ -0,0 +1,19 @@
Copyright (c) 2010- mruby developers
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

63
vendor/mruby/Makefile vendored Normal file
View file

@ -0,0 +1,63 @@
# mruby is using Rake (https://ruby.github.io/rake/) as a build tool.
RAKE = rake
DOCKER_COMPOSE = docker-compose
PRE_COMMIT = prek
define check_command
@command -v $(1) >/dev/null 2>&1 || { \
echo "Error: $(1) is not installed or not in PATH."; \
exit 1; \
}
endef
# For colors
ifneq ($(shell tty -s),)
CYAN := $(shell tput setaf 6)
RESET := $(shell tput sgr0)
else
CYAN :=
RESET :=
endif
.PHONY: all test clean check checkinstall checkupdate composecheck composetest check_rake check_docker_compose check_pre_commit help
.DEFAULT_GOAL := all
all: check_rake ## build all targets, install (locally) in-repo
$(RAKE)
test: check_rake all ## build and run all mruby tests
$(RAKE) test
clean: check_rake ## clean all built and in-repo installed artifacts
$(RAKE) clean
check: check_pre_commit ## run all prek hooks against all files
$(PRE_COMMIT) run --all-files
checkinstall: check_pre_commit ## install the prek hooks
$(PRE_COMMIT) install
checkupdate: check_pre_commit ## check the prek hooks for updates
$(PRE_COMMIT) autoupdate
composecheck: check_docker_compose check_pre_commit ## run all prek hooks against all files with docker-compose
$(DOCKER_COMPOSE) -p mruby run test $(PRE_COMMIT) run --all-files
composetest: check_docker_compose ## build and run all mruby tests with docker-compose
$(DOCKER_COMPOSE) -p mruby run test
check_rake: ## check if Rake is installed
$(call check_command, $(RAKE))
check_docker_compose: ## check if docker-compose is installed
$(call check_command, $(DOCKER_COMPOSE))
check_pre_commit: ## check if prek is installed
$(call check_command, $(PRE_COMMIT))
help: ## display this help message
@echo "Usage: make <target>"
@echo
@echo "Available targets:"
@grep -E '^[a-z_-]+:.*##' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*## *"}; {printf " $(CYAN)%-20s$(RESET) %s\n", $$1, $$2}'

367
vendor/mruby/NEWS.md vendored Normal file
View file

@ -0,0 +1,367 @@
# User visible changes in `mruby4.0` from `mruby3.4`
"**_NOTE_**:" are changes to be aware of.
# The language
## Pattern Matching
mruby now supports pattern matching (case/in) syntax:
- Basic pattern matching with `case`/`in` syntax ([dadfac6](https://github.com/mruby/mruby/commit/dadfac6))
- Array pattern matching ([ec67fd9](https://github.com/mruby/mruby/commit/ec67fd9))
- Hash pattern matching ([2147263](https://github.com/mruby/mruby/commit/2147263))
- Find pattern matching (`[*pre, target, *post]`) ([6c4d98b](https://github.com/mruby/mruby/commit/6c4d98b))
- Pin operator (`^variable`) ([1de6340](https://github.com/mruby/mruby/commit/1de6340))
- Guard clauses (`if`/`unless` conditions) ([07ac110](https://github.com/mruby/mruby/commit/07ac110))
- One-line pattern matching (`expr in pattern`) ([e76ce24](https://github.com/mruby/mruby/commit/e76ce24))
- Brace-less hash pattern support ([e8096bf](https://github.com/mruby/mruby/commit/e8096bf))
## Other Language Changes
- `&nil` in formal parameters to explicitly opt out of block arguments ([b07518e](https://github.com/mruby/mruby/commit/b07518e))
- Trailing comma in method definition parameters: `def foo(a, b,)` ([f78334b](https://github.com/mruby/mruby/commit/f78334b))
- Array/Hash/String subclasses can now override `[]` and `[]=` methods ([#6675](https://github.com/mruby/mruby/pull/6675))
- `OP_SETIDX` optimization for Array and Hash ([ddd8fe1](https://github.com/mruby/mruby/commit/ddd8fe1))
- `case`/`in` without `else` now raises `NoMatchingPatternError` ([d8de35b](https://github.com/mruby/mruby/commit/d8de35b))
- Allow compound statement in parenthesized argument context ([919cbd8](https://github.com/mruby/mruby/commit/919cbd8))
# Changes in C API
- **_NOTE_**: `mrb_alloca()` renamed to `mrb_temp_alloc()` ([7fe5c2e](https://github.com/mruby/mruby/commit/7fe5c2e))
- **_NOTE_**: `mruby/ext/io.h` renamed to `mruby/io.h` ([2813f79](https://github.com/mruby/mruby/commit/2813f79))
- `mrb_gc_add_region()` for contiguous heap region support ([072855a](https://github.com/mruby/mruby/commit/072855a))
- `mrb_class_outer()` to get the outer class/module ([3a1b771](https://github.com/mruby/mruby/commit/3a1b771))
- `MRB_ENSURE()` macro for exception-safe cleanup ([3ac682b](https://github.com/mruby/mruby/commit/3ac682b))
- `mrb_time_get_tm()` for accessing struct tm ([daaaafe](https://github.com/mruby/mruby/commit/daaaafe))
- `MRB_OPEN_FAILURE()` macro for checking mrb_open result ([40b0cb9](https://github.com/mruby/mruby/commit/40b0cb9))
- `mrb_print_error()` now handles NULL gracefully ([8e50a45](https://github.com/mruby/mruby/commit/8e50a45))
- `mrb_open()` returns mrb_state with exc set on init failure ([05ffe0c](https://github.com/mruby/mruby/commit/05ffe0c))
- `mrb_utf8_to_buf()` for UTF-8 encoding consolidation ([7e28e68](https://github.com/mruby/mruby/commit/7e28e68))
- `kh_is_end()` macro for safe khash iteration ([893cc75](https://github.com/mruby/mruby/commit/893cc75))
- `mrb_bigint_p()` always defined regardless of bigint gem presence ([6c4a8c0](https://github.com/mruby/mruby/commit/6c4a8c0))
- `RInteger` and `RFloat` added to `RVALUE` union ([13dbca0](https://github.com/mruby/mruby/commit/13dbca0))
# ROM Method Tables
All built-in classes and most extension gems now use read-only method
tables stored in `.rodata` instead of heap-allocated hash tables. Method
definitions no longer consume heap memory, significantly reducing memory
footprint for embedded use.
Core classes converted: BasicObject, Object, Module, Class, Kernel,
String, Array, Hash, Numeric, Integer, Float, NilClass, TrueClass,
FalseClass, Range, Symbol, Exception, Proc.
Extension gems converted: mruby-string-ext, mruby-array-ext, mruby-set,
mruby-struct, mruby-class-ext, mruby-numeric-ext, mruby-random,
mruby-kernel-ext, mruby-complex, mruby-rational, mruby-io, mruby-socket,
mruby-method, mruby-metaprog, mruby-time, mruby-hash-ext, mruby-proc-ext,
mruby-symbol-ext, mruby-range-ext, mruby-object-ext.
# GC and Memory
- **_NOTE_**: `MRB_NO_PRESYM` removed; presym is now always enabled ([81689045](https://github.com/mruby/mruby/commit/81689045))
- Replace `gcnext` gray linked list with fixed-size gray stack, reducing per-object overhead ([31fea170](https://github.com/mruby/mruby/commit/31fea170))
- `mrb_gc_add_region()` for providing contiguous memory buffers as GC heap pages ([072855a](https://github.com/mruby/mruby/commit/072855a))
- Chunk-based pool for symbol string allocation ([e05bd8f](https://github.com/mruby/mruby/commit/e05bd8f))
- Reduce `IV_INITIAL_SIZE` from 4 to 2 ([6bd1f51](https://github.com/mruby/mruby/commit/6bd1f51))
- Lossless float encoding using rotation in word boxing ([b6148c8](https://github.com/mruby/mruby/commit/b6148c8))
- Lossless rotation encoding for 32-bit float32 word boxing ([14a5cfb](https://github.com/mruby/mruby/commit/14a5cfb))
- Consolidated irep allocation for .mrb loading ([74fb045](https://github.com/mruby/mruby/commit/74fb045))
- Object shapes (hidden classes) for `MRB_TT_OBJECT` IV storage, sharing key layouts across objects with the same instance variable assignment order ([8d10056](https://github.com/mruby/mruby/commit/8d10056))
# Build & Configuration
- **_NOTE_**: `MRB_WORDBOX_NO_FLOAT_TRUNCATE` renamed to `MRB_WORDBOX_NO_INLINE_FLOAT` (old name still works) ([59e1fe2](https://github.com/mruby/mruby/commit/59e1fe2))
- **_NOTE_**: `MRB_INT64` on 32-bit now requires `MRB_NO_BOXING` (other boxing modes cannot guarantee alignment for heap-allocated 64-bit integers) ([eaaa66b](https://github.com/mruby/mruby/commit/eaaa66b))
- Amalgamation support via `rake amalgam` task ([d995ca2](https://github.com/mruby/mruby/commit/d995ca2))
- New Platform: Cosmopolitan Libc ([#6681](https://github.com/mruby/mruby/pull/6681))
- Emscripten: use native WASM exception handling ([ca364e3](https://github.com/mruby/mruby/commit/ca364e3))
- HAL (Hardware Abstraction Layer) for platform abstraction in mruby-io, mruby-socket, mruby-dir, mruby-task ([74ca22f](https://github.com/mruby/mruby/commit/74ca22f))
- `MRUBY_MIRB_READLINE` environment variable to control readline library selection ([0aafb83](https://github.com/mruby/mruby/commit/0aafb83))
- MSYS2 drive letter support in build script ([77f6ffe](https://github.com/mruby/mruby/commit/77f6ffe))
- Inter-gem headers separated from external API headers ([#6671](https://github.com/mruby/mruby/pull/6671))
# Changes in mrbgems
## New Gems
- **mruby-task**: Cooperative multitasking with preemptive scheduling ([ae0d7a0](https://github.com/mruby/mruby/commit/ae0d7a0))
- **mruby-benchmark**: Benchmarking gem ([2f40f3d](https://github.com/mruby/mruby/commit/2f40f3d))
- **mruby-strftime**: Time#strftime implementation ([b31e22f](https://github.com/mruby/mruby/commit/b31e22f))
## mruby-bin-mirb Improvements
- Custom multi-line editor replacing readline ([527018c](https://github.com/mruby/mruby/commit/527018c))
- Syntax highlighting for keywords, strings, result values, hash key symbols ([624272b](https://github.com/mruby/mruby/commit/624272b), [1713d4a](https://github.com/mruby/mruby/commit/1713d4a))
- Automatic light/dark theme detection via OSC 11 ([db4c8d9](https://github.com/mruby/mruby/commit/db4c8d9))
- Tab completion support ([2f15282](https://github.com/mruby/mruby/commit/2f15282))
- Colored output for prompts and errors ([b36e0b4](https://github.com/mruby/mruby/commit/b36e0b4))
- Auto-indentation and auto-dedent ([d52f318](https://github.com/mruby/mruby/commit/d52f318), [e901b6d](https://github.com/mruby/mruby/commit/e901b6d))
- Command history with Up/Down navigation ([5f85c1b](https://github.com/mruby/mruby/commit/5f85c1b))
- Line numbers in multi-line prompts ([5a3f0e2](https://github.com/mruby/mruby/commit/5a3f0e2))
- UTF-8 multibyte character support ([4a97da3](https://github.com/mruby/mruby/commit/4a97da3))
## mruby-bigint Improvements
- Toom-3 multiplication for large numbers ([99620804](https://github.com/mruby/mruby/commit/99620804))
- Karatsuba multiplication for medium-sized numbers ([85e81072](https://github.com/mruby/mruby/commit/85e81072))
- Balance multiplication for asymmetric operands ([0220ec2b](https://github.com/mruby/mruby/commit/0220ec2b))
- Divide-and-conquer optimization for `to_s` ([990ff90f](https://github.com/mruby/mruby/commit/990ff90f))
- Consolidated mpn layer for low-level limb operations ([9ef3362f](https://github.com/mruby/mruby/commit/9ef3362f))
- Always use 32-bit limbs by default ([c747c77f](https://github.com/mruby/mruby/commit/c747c77f))
## Other Gem Changes
- **_NOTE_**: `Hash#deconstruct_keys` removed for CRuby compatibility ([34b9412](https://github.com/mruby/mruby/commit/34b9412))
- **mruby-enum-lazy**: Fix `Lazy#flat_map` to handle non-enumerable block return values ([#6765](https://github.com/mruby/mruby/pull/6765))
- **mruby-array-ext**: Add `Array#find` and `Array#rfind` methods
- **mruby-io**: Add `IO#putc` and `Kernel#putc` ([baff6e6](https://github.com/mruby/mruby/commit/baff6e6))
- **mruby-random**: Replace xoshiro with PCG for better memory efficiency ([f1bab01](https://github.com/mruby/mruby/commit/f1bab01))
- **mruby-compiler**: Variable-sized AST nodes for reduced memory usage
- **mruby-compiler**: `no_return_value` context flag for script optimization ([613b03a](https://github.com/mruby/mruby/commit/613b03a))
- `initialize_copy` and `respond_to_missing?` defined as private ([#6708](https://github.com/mruby/mruby/pull/6708))
- Struct keyword argument initialization ([#6574](https://github.com/mruby/mruby/pull/6574))
# Compiler Improvements
- Variable-sized AST nodes for reduced memory consumption ([821b989](https://github.com/mruby/mruby/commit/821b989))
- Pattern matching bytecode optimizations ([21d4135](https://github.com/mruby/mruby/commit/21d4135))
- Optimized masgn to generate literals directly into target registers ([fb5d966](https://github.com/mruby/mruby/commit/fb5d966))
- Optimized splat of literal arrays in args/literals ([1cb8d73](https://github.com/mruby/mruby/commit/1cb8d73))
- Early termination after too many parse errors ([510ebd7](https://github.com/mruby/mruby/commit/510ebd7))
- Chunk array literals at 64 elements to reduce register pressure ([f98d641](https://github.com/mruby/mruby/commit/f98d641))
- Chunk `%w()` and `%i()` literals to reduce register pressure ([62cf0dc](https://github.com/mruby/mruby/commit/62cf0dc))
# VM Optimizations
New super-instructions that fuse common opcode sequences to reduce bytecode size and improve performance:
- `OP_SEND0`/`OP_SSEND0`: Zero-argument method call, avoiding argument count setup ([9123ef4](https://github.com/mruby/mruby/commit/9123ef4))
- `OP_TDEF`/`OP_SDEF`: Fused method definition combining TCLASS/SCLASS+METHOD+DEF into single instruction, saving 4 bytes per method ([8d4f47e](https://github.com/mruby/mruby/commit/8d4f47e))
- `OP_GETIDX0`: Fast path for `array[0]` and `Array#first` access ([680f7ec](https://github.com/mruby/mruby/commit/680f7ec))
- `OP_ADDILV`/`OP_SUBILV`: Local variable increment/decrement fusion for `i += n` patterns ([43f64b9](https://github.com/mruby/mruby/commit/43f64b9))
- `OP_RETSELF`: Single-byte instruction for `return self` pattern ([a71db8c](https://github.com/mruby/mruby/commit/a71db8c))
- `OP_RETNIL`: Single-byte instruction for `return nil` pattern ([64e30bf](https://github.com/mruby/mruby/commit/64e30bf))
- `OP_RETTRUE`/`OP_RETFALSE`: Single-byte instructions for `return true`/`return false` patterns ([0b15727](https://github.com/mruby/mruby/commit/0b15727))
- `OP_MATCHERR`: Pattern matching error with conditional execution ([944168a](https://github.com/mruby/mruby/commit/944168a))
- `OP_BLKCALL`: Direct block call for `yield`, bypassing method dispatch (13-17% faster) ([3aa2872](https://github.com/mruby/mruby/commit/3aa2872))
Other optimizations:
- 1.5x stack growth instead of linear growth for reduced reallocations ([f7988c93](https://github.com/mruby/mruby/commit/f7988c93))
- Skip keyword argument hash duplication ([5970e350](https://github.com/mruby/mruby/commit/5970e350))
# Fixed GitHub Issues
- [#5531](https://github.com/mruby/mruby/issues/5531) Hash recursion detection
- [#6506](https://github.com/mruby/mruby/issues/6506) Constant lookup in singleton class
- [#6507](https://github.com/mruby/mruby/issues/6507) tally multi-values
- [#6508](https://github.com/mruby/mruby/issues/6508) Enumerable#sum index
- [#6509](https://github.com/mruby/mruby/issues/6509) scope_new nregs initialization
- [#6515](https://github.com/mruby/mruby/issues/6515) y.tab.c in repository
- [#6516](https://github.com/mruby/mruby/issues/6516) Private backquote
- [#6554](https://github.com/mruby/mruby/issues/6554) Socket private #initialize
- [#6570](https://github.com/mruby/mruby/issues/6570) instance_eval crash
- [#6613](https://github.com/mruby/mruby/issues/6613) const_added hook during bootstrapping
- [#6635](https://github.com/mruby/mruby/issues/6635), [#6636](https://github.com/mruby/mruby/issues/6636) Colon3 constant lookup
- [#6637](https://github.com/mruby/mruby/issues/6637) arm64 mingw64 builtin setjmp/longjmp
- [#6642](https://github.com/mruby/mruby/issues/6642) Task segfault when sleep called from C
- [#6645](https://github.com/mruby/mruby/issues/6645) Set memory leak from double initialization
- [#6646](https://github.com/mruby/mruby/issues/6646) IO#gets negative length
- [#6647](https://github.com/mruby/mruby/issues/6647) IO#ungetc buffer overflow
- [#6648](https://github.com/mruby/mruby/issues/6648) sprintf buffer overread
- [#6649](https://github.com/mruby/mruby/issues/6649) Array#sort! use-after-realloc
- [#6650](https://github.com/mruby/mruby/issues/6650) Array#fill validation
- [#6652](https://github.com/mruby/mruby/issues/6652) Array comparison use-after-realloc
- [#6657](https://github.com/mruby/mruby/issues/6657) Exception handling for ||= on class variables
- [#6659](https://github.com/mruby/mruby/issues/6659) Super with keyword arguments
- [#6660](https://github.com/mruby/mruby/issues/6660) Regression on struct/array/hash == override with super
- [#6662](https://github.com/mruby/mruby/issues/6662) Array set operations use-after-free
- [#6664](https://github.com/mruby/mruby/issues/6664) Set#flatten memory leak
- [#6666](https://github.com/mruby/mruby/issues/6666) Regexp literal with encoding
- [#6668](https://github.com/mruby/mruby/issues/6668) Method#== for aliased methods and comparison bug
- [#6671](https://github.com/mruby/mruby/issues/6671) Separate inter-gem headers from external API headers
- [#6674](https://github.com/mruby/mruby/issues/6674) Document pattern matching limitations
- [#6675](https://github.com/mruby/mruby/issues/6675) Allow Hash#[] to be aliased again
- [#6687](https://github.com/mruby/mruby/issues/6687) Expand MRB_SYM/MRB_GVSYM support for symbols with special characters
- [#6698](https://github.com/mruby/mruby/issues/6698) Bigint tests fail on architectures other than x86_64 and i386
- [#6701](https://github.com/mruby/mruby/issues/6701) Heap-use-after-free in mrb_vm_exec involving mruby-rational / mruby-bigint
- [#6702](https://github.com/mruby/mruby/issues/6702) mruby-bigint doesn't compile in C++ project
- [#6704](https://github.com/mruby/mruby/issues/6704) Heap-buffer-overflow in mrb_vm_exec via malformed source code
- [#6705](https://github.com/mruby/mruby/issues/6705) Can't get outer class of an object in C
- [#6713](https://github.com/mruby/mruby/issues/6713) mruby-polarssl not work
- [#6720](https://github.com/mruby/mruby/issues/6720) Random float range: different behavior from CRuby
- [#6722](https://github.com/mruby/mruby/issues/6722) RBreak size overflow on 32-bit platforms with MRB_NO_BOXING
- [#6740](https://github.com/mruby/mruby/issues/6740) `%w()`/`%i()` register pressure with large literals
- [#6741](https://github.com/mruby/mruby/issues/6741) `case`/`in` without `else` should raise `NoMatchingPatternError`
- [#6760](https://github.com/mruby/mruby/issues/6760) `mrb_gc_unregister()` not removing all matching entries
# Merged Pull Requests
- [#6418](https://github.com/mruby/mruby/pull/6418) Add `ls-lint` with GitHub Actions
- [#6492](https://github.com/mruby/mruby/pull/6492) fix a typo, update specs
- [#6493](https://github.com/mruby/mruby/pull/6493) Fix TYPO in memory.md
- [#6495](https://github.com/mruby/mruby/pull/6495) Remove `MRB_ENDIAN_LOHI()` that is no longer in use
- [#6497](https://github.com/mruby/mruby/pull/6497) gha: update `build.yml` try `windows-2025` image
- [#6498](https://github.com/mruby/mruby/pull/6498) Clean up and standardize the pre-commit config
- [#6501](https://github.com/mruby/mruby/pull/6501) Update pre-commit Node.js version to `v22.14.0 LTS`
- [#6502](https://github.com/mruby/mruby/pull/6502) pre-commit: update prettier to the latest version
- [#6503](https://github.com/mruby/mruby/pull/6503) misc: fix typos
- [#6505](https://github.com/mruby/mruby/pull/6505) mrbgems: fix spelling
- [#6510](https://github.com/mruby/mruby/pull/6510) Fixed class method visibility via `module_function`
- [#6511](https://github.com/mruby/mruby/pull/6511) Exclude the external project "lrama" from pre-commit
- [#6513](https://github.com/mruby/mruby/pull/6513) mruby 3.4.0 released
- [#6517](https://github.com/mruby/mruby/pull/6517) core/codegen.c: remove unneeded duplicate semicolon
- [#6518](https://github.com/mruby/mruby/pull/6518) Change mrbc_args.flags bit width from 2 to 3
- [#6519](https://github.com/mruby/mruby/pull/6519) Add `tools/lrama` to `.prettierignore`
- [#6520](https://github.com/mruby/mruby/pull/6520) pre-commit: autoupdate and update node LTS version
- [#6521](https://github.com/mruby/mruby/pull/6521) Add codespell config file `.codespellrc`
- [#6522](https://github.com/mruby/mruby/pull/6522) gha: label more files
- [#6523](https://github.com/mruby/mruby/pull/6523) add `rand(Range)` and unify implementations of `Random#rand` and `Kernel#rand`
- [#6524](https://github.com/mruby/mruby/pull/6524) Fix Kernel#p when no argument
- [#6525](https://github.com/mruby/mruby/pull/6525) Skip adding empty input to mirb history
- [#6526](https://github.com/mruby/mruby/pull/6526) Add build config for Luckfox Pico embedded SBC
- [#6528](https://github.com/mruby/mruby/pull/6528) misc: fix spelling
- [#6530](https://github.com/mruby/mruby/pull/6530) Revert "class.c (find_visibility_scope): when callinfo returns, \*ep == NULL; #6512"
- [#6531](https://github.com/mruby/mruby/pull/6531) Improve method table performance by rehashing at 75% load factor
- [#6532](https://github.com/mruby/mruby/pull/6532) Reverted method table optimizations to prioritize memory savings
- [#6533](https://github.com/mruby/mruby/pull/6533) Fix calling `extended` callback
- [#6534](https://github.com/mruby/mruby/pull/6534) Add descriptive comment to mrb_read_float function
- [#6535](https://github.com/mruby/mruby/pull/6535) Added descriptive comments for functions/macros in src/mempool.c
- [#6536](https://github.com/mruby/mruby/pull/6536) Add descriptive comments to public functions in src/debug.c
- [#6537](https://github.com/mruby/mruby/pull/6537) Updated comments in `cdump.c` to remove the `@brief` tag
- [#6539](https://github.com/mruby/mruby/pull/6539) Add descriptive comments for functions in src/load.c
- [#6540](https://github.com/mruby/mruby/pull/6540) Add descriptive comments to MRB_API functions in object.c
- [#6541](https://github.com/mruby/mruby/pull/6541) Add descriptive comments for MRB_API functions in src/array.c
- [#6542](https://github.com/mruby/mruby/pull/6542) Add descriptive comments to MRB_API functions in src/symbol.c
- [#6543](https://github.com/mruby/mruby/pull/6543) Add descriptive comments to several functions in src/dump.c
- [#6544](https://github.com/mruby/mruby/pull/6544) Fix build strings that must be mutable
- [#6545](https://github.com/mruby/mruby/pull/6545) Add descriptive comments for MRB_API functions in src/class.c
- [#6548](https://github.com/mruby/mruby/pull/6548) Add descriptive comments to MRB_API functions in src/etc.c
- [#6549](https://github.com/mruby/mruby/pull/6549) Add descriptive comments to kernel functions
- [#6550](https://github.com/mruby/mruby/pull/6550) Add descriptive comments for MRB_API functions in src/proc.c
- [#6551](https://github.com/mruby/mruby/pull/6551) Add descriptive comments for MRB_API functions in src/state.c
- [#6552](https://github.com/mruby/mruby/pull/6552) Fix: Correct placement of comments in src/variable.c
- [#6553](https://github.com/mruby/mruby/pull/6553) Add descriptive comments for MRB_API functions in src/vm.c
- [#6555](https://github.com/mruby/mruby/pull/6555) `mrb_mt_foreach()` needs to update the pointer at each loop
- [#6556](https://github.com/mruby/mruby/pull/6556) `iv_foreach()` needs to update the pointer at each loop
- [#6560](https://github.com/mruby/mruby/pull/6560) Refactor: Improve Set GC marking and freeing
- [#6561](https://github.com/mruby/mruby/pull/6561) pre-commit updates and fix prettier entrypoint
- [#6562](https://github.com/mruby/mruby/pull/6562) misc: fix spelling word case
- [#6563](https://github.com/mruby/mruby/pull/6563) pre-commit add rubocop with one rule spaces for indentation
- [#6564](https://github.com/mruby/mruby/pull/6564) Remove jumanjihouse pre-commit hooks no longer maintained
- [#6565](https://github.com/mruby/mruby/pull/6565) Rubocop: fix target Ruby version; add two more cops; fix lint error
- [#6566](https://github.com/mruby/mruby/pull/6566) Removed unreferenced variables in `CrossBuild#run_bintest`
- [#6567](https://github.com/mruby/mruby/pull/6567) Avoid array object creation in `cmd_bin` method in bintest
- [#6568](https://github.com/mruby/mruby/pull/6568) mruby-bin-debugger depends on mruby-bin-mrbc in bintest
- [#6569](https://github.com/mruby/mruby/pull/6569) sed s/Mruby/MRuby/g
- [#6571](https://github.com/mruby/mruby/pull/6571) Update limitations.md to add behavior on small hash
- [#6572](https://github.com/mruby/mruby/pull/6572) Add Claude Code GitHub Workflow
- [#6573](https://github.com/mruby/mruby/pull/6573) pre-commit fixes and updates
- [#6574](https://github.com/mruby/mruby/pull/6574) Support initializing structs via keyword arguments
- [#6575](https://github.com/mruby/mruby/pull/6575) Fix typo in file time methods
- [#6581](https://github.com/mruby/mruby/pull/6581) Merge `mrb_obj_iv_inspect()` into `mrb_obj_inspect()`
- [#6582](https://github.com/mruby/mruby/pull/6582) Stricter type tag in `mrb_obj_alloc()`
- [#6583](https://github.com/mruby/mruby/pull/6583) Add fallback to local build_config.rb before using default configuration
- [#6585](https://github.com/mruby/mruby/pull/6585) Fix typo in mruby3.2 docs
- [#6586](https://github.com/mruby/mruby/pull/6586) Makefile: refactor add docs and add command line `help` target
- [#6587](https://github.com/mruby/mruby/pull/6587) Add Set#hash tests
- [#6588](https://github.com/mruby/mruby/pull/6588) Add CodeQL Analysis for GitHub Actions
- [#6589](https://github.com/mruby/mruby/pull/6589) Add pre-commit hook `check-zip-file-is-not-committed`
- [#6591](https://github.com/mruby/mruby/pull/6591) mruby-eval fix license link in README
- [#6593](https://github.com/mruby/mruby/pull/6593) README: Add Contributors Avatars, Star History, Table of Contents
- [#6598](https://github.com/mruby/mruby/pull/6598) Fix heap buffer overflow in `#method_missing`
- [#6599](https://github.com/mruby/mruby/pull/6599) pre-commit: run `markdown-link-check`, `oxipng`, `prettier` manually
- [#6600](https://github.com/mruby/mruby/pull/6600) `dreamcast_shelf build config`: update to use KallistiOS wrappers
- [#6601](https://github.com/mruby/mruby/pull/6601) fix: skip local build_config.rb when working in MRUBY_ROOT
- [#6602](https://github.com/mruby/mruby/pull/6602) Improved iseq annotations for `new` and `!=`
- [#6604](https://github.com/mruby/mruby/pull/6604) pre-commit config updates
- [#6607](https://github.com/mruby/mruby/pull/6607) fix bigint on raspberry pi
- [#6610](https://github.com/mruby/mruby/pull/6610) Extract golden ratio prime into constant
- [#6614](https://github.com/mruby/mruby/pull/6614) Fix uninitialized variable in io_gets causing segmentation fault
- [#6617](https://github.com/mruby/mruby/pull/6617) Fix various minor problems and speed up build
- [#6618](https://github.com/mruby/mruby/pull/6618) Stop generating unnecessary C++ files in mruby-bin-mruby
- [#6621](https://github.com/mruby/mruby/pull/6621) Set up all GEMS before mruby core tasks definition
- [#6624](https://github.com/mruby/mruby/pull/6624) Fixed wrong `MRuby::Build.current` at the top level of `mrbgem.rake`
- [#6628](https://github.com/mruby/mruby/pull/6628) Revert `File.absolute_path` logic
- [#6629](https://github.com/mruby/mruby/pull/6629) pre-commit update
- [#6631](https://github.com/mruby/mruby/pull/6631) Revert "Rakefile: make the whole thing parallel unless SERIAL=1"
- [#6633](https://github.com/mruby/mruby/pull/6633) Fix a heap-buffer-overflow in str strip! methods
- [#6643](https://github.com/mruby/mruby/pull/6643) Fix crash caused by an incorrect node type check in `codegen_masgn`
- [#6651](https://github.com/mruby/mruby/pull/6651) Address stack-use-after-return in the mruby bigint implementation
- [#6653](https://github.com/mruby/mruby/pull/6653) Improve HAL-related components for MinGW
- [#6655](https://github.com/mruby/mruby/pull/6655) Preventing Memory Leaks in `Array#__combination_init`
- [#6656](https://github.com/mruby/mruby/pull/6656) Fix integer overflow in allocation size calculation
- [#6663](https://github.com/mruby/mruby/pull/6663) Added the `kh_is_end()` macro function
- [#6665](https://github.com/mruby/mruby/pull/6665) Fixed use-after-free with `Set#join`
- [#6670](https://github.com/mruby/mruby/pull/6670) Arranging VM dispatch macros
- [#6673](https://github.com/mruby/mruby/pull/6673) Adjust broken license links; clean up Markdown
- [#6677](https://github.com/mruby/mruby/pull/6677) gha: run pre-commit with `--color=always`
- [#6678](https://github.com/mruby/mruby/pull/6678) Put ls-lint and pre-commit in separate workflow files
- [#6679](https://github.com/mruby/mruby/pull/6679) pre-commit autoupdate; update node and prettier
- [#6681](https://github.com/mruby/mruby/pull/6681) Add Cosmopolitan Libc build configuration
- [#6689](https://github.com/mruby/mruby/pull/6689) docs: fix pre-commit manual hooks; fix link
- [#6694](https://github.com/mruby/mruby/pull/6694) Fix mirb build under Cosmopolitan
- [#6695](https://github.com/mruby/mruby/pull/6695) Dependabot: add a cooldown period for new releases
- [#6696](https://github.com/mruby/mruby/pull/6696) Fix parse error with required kwargs and omitted parens
- [#6699](https://github.com/mruby/mruby/pull/6699) Fix mruby-task for PicoRuby Integration
- [#6700](https://github.com/mruby/mruby/pull/6700) Fix float/double pack/unpack on s390x
- [#6706](https://github.com/mruby/mruby/pull/6706) Refactor task class to use symbol IDs
- [#6708](https://github.com/mruby/mruby/pull/6708) `initialize_copy` and `respond_to_missing?` defined as private
- [#6709](https://github.com/mruby/mruby/pull/6709) Add the `MRB_ENSURE()` macro
- [#6711](https://github.com/mruby/mruby/pull/6711) Fix out of bounds read and write in IO.select
- [#6714](https://github.com/mruby/mruby/pull/6714) Fix OP_DEBUG operand type and add NULL check for debug_op_hook
- [#6716](https://github.com/mruby/mruby/pull/6716) Fixes identity for proc object
- [#6717](https://github.com/mruby/mruby/pull/6717) Fix mruby-task: wrapping by critical section and setting initial task receiver
- [#6718](https://github.com/mruby/mruby/pull/6718) Add installation instructions for conda and Homebrew
- [#6723](https://github.com/mruby/mruby/pull/6723) Add `RInteger` and `RFloat` to `RVALUE`
- [#6727](https://github.com/mruby/mruby/pull/6727) Language documentation: update wording of "overloading" section
- [#6729](https://github.com/mruby/mruby/pull/6729) Simplifying dependency addition for gensym task
- [#6730](https://github.com/mruby/mruby/pull/6730) Simplifying presym file generation actions
- [#6733](https://github.com/mruby/mruby/pull/6733) Include `mruby/presym.h` for all source files
- [#6734](https://github.com/mruby/mruby/pull/6734) Chunk array literals at 64 elements to reduce register pressure
- [#6735](https://github.com/mruby/mruby/pull/6735) Prevent full recompilation without changes to presym file
- [#6739](https://github.com/mruby/mruby/pull/6739) Fix MSYS2 build error with drive letters
- [#6743](https://github.com/mruby/mruby/pull/6743) Chunk `%w()` and `%i()` literals to reduce register pressure
- [#6744](https://github.com/mruby/mruby/pull/6744) Raise `NoMatchingPatternError` in `case`/`in` without `else`
- [#6747](https://github.com/mruby/mruby/pull/6747) Correctly handle empty hash as default named argument
- [#6749](https://github.com/mruby/mruby/pull/6749) Fix microcontroller profile
- [#6750](https://github.com/mruby/mruby/pull/6750) Fix out-of-bounds read and divide-by-zero in `Array#product`
- [#6752](https://github.com/mruby/mruby/pull/6752) Fix `attr_reader`-generated methods accepting extra arguments
- [#6753](https://github.com/mruby/mruby/pull/6753) Further optimize `Array#product`
- [#6754](https://github.com/mruby/mruby/pull/6754) Mark `attr_reader` procs as noarg
- [#6755](https://github.com/mruby/mruby/pull/6755) Reload `ci` after `mrb_hash_delete_key()` in keyword argument handling
- [#6756](https://github.com/mruby/mruby/pull/6756) Avoid impact of object modifications caused by `mrb_vm_exec()` calls
- [#6758](https://github.com/mruby/mruby/pull/6758) Don't assign result of `mrb_funcall()` directly to `regs`
- [#6759](https://github.com/mruby/mruby/pull/6759) Define `mrb_bigint_p()` always
- [#6761](https://github.com/mruby/mruby/pull/6761) Fix `mrb_gc_unregister()` to remove all matching entries
- [#6762](https://github.com/mruby/mruby/pull/6762) Write generated test C files atomically to avoid build race condition
- [#6765](https://github.com/mruby/mruby/pull/6765) Fix `Lazy#flat_map` to handle non-enumerable block return values
- [#6767](https://github.com/mruby/mruby/pull/6767) Allow compound statement in parenthesized argument context
- [#6780](https://github.com/mruby/mruby/pull/6780) Fix `String#prepend` with self-referencing arguments
- [#6781](https://github.com/mruby/mruby/pull/6781) Protect `sprintf` format string from mutation during callbacks
- [#6783](https://github.com/mruby/mruby/pull/6783) Pin GitHub Actions workflows to commit hashes
# Security Fixes
- Buffer overflow in bigint uadd ([3f2611e](https://github.com/mruby/mruby/commit/3f2611e))
- Stack buffer overflow in Montgomery reduction ([edce0a3](https://github.com/mruby/mruby/commit/edce0a3))
- Buffer overflow in pack_uu encoding ([2993302](https://github.com/mruby/mruby/commit/2993302))
- Buffer overflow in IO#ungetc ([01ab2ff](https://github.com/mruby/mruby/commit/01ab2ff))
- Heap-buffer-overflow in pattern alternation codegen ([eea9e30](https://github.com/mruby/mruby/commit/eea9e30))
- Out of bounds read and write in IO.select ([44831711](https://github.com/mruby/mruby/commit/44831711))
- Off-by-one in bounds check for symbol names and pool strings in load.c ([b3b8c01](https://github.com/mruby/mruby/commit/b3b8c01))
- Use-after-free in Set operations ([a6b55e7](https://github.com/mruby/mruby/commit/a6b55e7))
- Use-after-free in Array set operations ([729b84c](https://github.com/mruby/mruby/commit/729b84c))
- Use-after-free in Set#join ([0e653eb](https://github.com/mruby/mruby/commit/0e653eb))
- Use-after-realloc in Array#sort! ([eb39897](https://github.com/mruby/mruby/commit/eb39897))
- Heap-use-after-free in insertion_sort ([099d2c47](https://github.com/mruby/mruby/commit/099d2c47))
- Integer overflow in str_check_length ([6afff1c3](https://github.com/mruby/mruby/commit/6afff1c3))
- Integer overflow in Integer#lcm ([070bef24](https://github.com/mruby/mruby/commit/070bef24))
- Heap buffer overflow in `#method_missing` ([550d10a](https://github.com/mruby/mruby/commit/550d10a))
- Out-of-bounds read and divide-by-zero in `Array#product` ([8441eaf](https://github.com/mruby/mruby/commit/8441eaf))
- Heap buffer overflow in `String#prepend` with self-referencing arguments ([18ba026](https://github.com/mruby/mruby/commit/18ba026))
- Use-after-free in `sprintf` via `to_s` callback mutating format string ([48fc422](https://github.com/mruby/mruby/commit/48fc422))
- Multiple memory leak fixes in bigint, Set, Array, and Task gems

186
vendor/mruby/README.md vendored Normal file
View file

@ -0,0 +1,186 @@
<div align="center">
<p>
<a href="https://mruby.org/">
<img src="https://avatars.githubusercontent.com/u/1796512?s=200&v=4"
alt="The mruby programming language" title="mruby">
</a>
</p>
<h1>mruby</h1>
<a href="https://github.com/marketplace/actions/super-linter">
<img src="https://github.com/mruby/mruby/actions/workflows/super-linter.yml/badge.svg"
alt="GitHub Super-Linter">
</a>
</div>
### Table of contents
- [What is mruby](#what-is-mruby)
- [How to get mruby](#how-to-get-mruby)
- [mruby homepage](#mruby-homepage)
- [Mailing list](#mailing-list)
- [How to compile, test, and install (mruby and gems)](#how-to-compile-test-and-install-mruby-and-gems)
- [Amalgamation (single-file build)](#amalgamation-single-file-build)
- [Building documentation](#building-documentation)
- [How to customize mruby (mrbgems)](#how-to-customize-mruby-mrbgems)
- [Index of Document](#index-of-document)
- [License](#license)
- [Note for License](#note-for-license)
- [How to Contribute](#how-to-contribute)
- [Star History](#star-history)
- [Contributors](#contributors)
## What is mruby
mruby is the lightweight implementation of the Ruby language complying to (part
of) the [ISO standard][ISO-standard] with more recent features provided by Ruby 4.x.
Also, its syntax is Ruby 4.x compatible.
You can link and embed mruby within your application. The "mruby" interpreter
program and the interactive "mirb" shell are provided as examples. You can also
compile Ruby programs into compiled byte code using the "mrbc" compiler. All
these tools are located in the "bin" directory. "mrbc" can also generate
compiled byte code in a C source file. See the "mrbtest" program under the
"test" directory for an example.
This achievement was sponsored by the Regional Innovation Creation R&D Programs
of the Ministry of Economy, Trade and Industry of Japan.
## How to get mruby
To get mruby, you can download the stable version 4.0.0 from the official mruby
GitHub repository or clone the trunk of the mruby source tree with the "git
clone" command. You can also install and compile mruby using [ruby-install](https://github.com/postmodern/ruby-install), [ruby-build](https://github.com/rbenv/ruby-build), [rvm](https://github.com/rvm/rvm), [conda](https://anaconda.org/channels/conda-forge/packages/mruby/overview) or [Homebrew](https://formulae.brew.sh/formula/mruby).
The release candidate version 4.0.0 of mruby can be downloaded via the following URL: [https://github.com/mruby/mruby/archive/4.0.0-rc3.zip](https://github.com/mruby/mruby/archive/4.0.0-rc3.zip)
The latest development version of mruby can be downloaded via the following URL: [https://github.com/mruby/mruby/zipball/master](https://github.com/mruby/mruby/zipball/master)
The trunk of the mruby source tree can be checked out with the
following command:
```console
$ git clone https://github.com/mruby/mruby.git
```
## mruby homepage
The URL of the mruby homepage is: <https://mruby.org>.
## Mailing list
We don't have a mailing list, but you can use [GitHub issues](https://github.com/mruby/mruby/issues).
## How to compile, test, and install (mruby and gems)
For the simplest case, type
```console
rake all test
```
See the [compile.md](doc/guides/compile.md) file for the detail.
## Amalgamation (single-file build)
mruby supports amalgamation, which combines all source files into a single
`mruby.c` and `mruby.h` for easy embedding (similar to SQLite).
```console
rake amalgam
```
Output files are generated in `build/host/amalgam/`. To use:
```console
gcc -I./build/host/amalgam your_app.c ./build/host/amalgam/mruby.c -o your_app -lm
```
## Building documentation
There are two sets of documentation in mruby: the mruby API (generated by YARD) and C API (Doxygen and Graphviz)
To build both of them, simply go
```console
rake doc
```
You can also view them in your browser
```console
rake view_api
rake view_capi
```
## How to customize mruby (mrbgems)
mruby contains a package manager called "mrbgems" that you can use to create
extensions in C and/or Ruby. For a guide on how to use mrbgems, consult the
[mrbgems.md](doc/guides/mrbgems.md) file, and for example code, refer to the
[examples/mrbgems/](examples/mrbgems) folder.
## Index of Document
<!--
This section is generated by `rake doc:update-index`.
All manual changes will get lost.
-->
<!-- BEGIN OF MRUBY DOCUMENT INDEX -->
- [About the Limitations of mruby](doc/limitations.md)
- [About Amalgamation (Single-File Build)](doc/guides/amalgamation.md)
- [C API Reference](doc/guides/capi.md)
- [About the Compile](doc/guides/compile.md)
- [About the Debugger with the `mrdb` Command](doc/guides/debugger.md)
- [About GC Arena](doc/guides/gc-arena-howto.md)
- [Getting Started with mruby](doc/guides/getting-started.md)
- [About the mruby directory structure](doc/guides/hier.md)
- [About Linking with `libmruby`](doc/guides/link.md)
- [About Memory Allocator Customization and Heap Regions](doc/guides/memory.md)
- [About Build-time Configurations](doc/guides/mrbconf.md)
- [About the Build-time Library Manager](doc/guides/mrbgems.md)
- [ROM Method Tables for Memory-Efficient Method Registration](doc/guides/rom-method-table.md)
- [About the Symbols](doc/guides/symbol.md)
- [Internal Implementation / About mruby Architecture](doc/internal/architecture.md)
- [Internal Implementation / About Value Boxing](doc/internal/boxing.md)
- [Internal Implementation / About mruby Virtual Machine Instructions](doc/internal/opcode.md)
<!-- END OF MRUBY DOCUMENT INDEX -->
## License
mruby is released under the [MIT License](LICENSE).
## Note for License
mruby has chosen a MIT License due to its permissive license allowing
developers to target various environments such as embedded systems.
However, the license requires the display of the copyright notice and license
information in manuals for instance. Doing so for big projects can be
complicated or troublesome. This is why mruby has decided to display "mruby
developers" as the copyright name to make it simple conventionally.
In the future, mruby might ask you to distribute your new code
(that you will commit,) under the MIT License as a member of
"mruby developers" but contributors will keep their copyright.
(We did not intend for contributors to transfer or waive their copyrights,
actual copyright holder name (contributors) will be listed in the [AUTHORS](AUTHORS)
file.)
Please ask us if you want to distribute your code under another license.
## How to Contribute
To contribute to mruby, please refer to the [contribution guidelines][contribution-guidelines] and send a pull request to the [mruby GitHub repository](https://github.com/mruby/mruby).
By contributing, you grant non-exclusive rights to your code under the MIT License.
## Star History
[![mruby Star History](https://api.star-history.com/svg?repos=mruby/mruby&type=Date)](https://www.star-history.com/#mruby/mruby&Date)
## Contributors
[![mruby Contributors](https://contrib.rocks/image?repo=mruby/mruby&anon=1&max=500)](https://github.com/mruby/mruby/graphs/contributors)
[ISO-standard]: https://www.iso.org/standard/59579.html
[contribution-guidelines]: CONTRIBUTING.md

102
vendor/mruby/Rakefile vendored Normal file
View file

@ -0,0 +1,102 @@
# Build description.
# basic build file for mruby
MRUBY_ROOT = File.dirname(File.expand_path(__FILE__))
MRUBY_BUILD_HOST_IS_CYGWIN = RUBY_PLATFORM.include?('cygwin')
MRUBY_BUILD_HOST_IS_OPENBSD = RUBY_PLATFORM.include?('openbsd')
Rake.verbose(false) if Rake.verbose == Rake::DSL::DEFAULT
$LOAD_PATH << File.join(MRUBY_ROOT, "lib")
# load build systems
require "mruby/core_ext"
require "mruby/build"
# load configuration file
MRUBY_CONFIG = MRuby::Build.mruby_config_path
load MRUBY_CONFIG
# set up all gems
MRuby.each_target do
gems.setup(self) if enable_gems?
end
# load basic rules
MRuby.each_target do |build|
build.define_rules
end
# load custom rules
load "#{MRUBY_ROOT}/tasks/core.rake"
load "#{MRUBY_ROOT}/tasks/mrblib.rake"
load "#{MRUBY_ROOT}/tasks/mrbgems.rake"
load "#{MRUBY_ROOT}/tasks/libmruby.rake"
load "#{MRUBY_ROOT}/tasks/bin.rake"
load "#{MRUBY_ROOT}/tasks/presym.rake"
load "#{MRUBY_ROOT}/tasks/test.rake"
load "#{MRUBY_ROOT}/tasks/benchmark.rake"
load "#{MRUBY_ROOT}/tasks/doc.rake"
load "#{MRUBY_ROOT}/tasks/install.rake"
load "#{MRUBY_ROOT}/tasks/amalgam.rake"
##############################
# generic build targets, rules
task :default => :all
desc "build all targets, install (locally) in-repo"
task :all => :gensym do
Rake::Task[:build].invoke
puts
puts "Build summary:"
puts
MRuby.each_target do |build|
build.print_build_summary
end
MRuby::Lockfile.write
end
task :build => MRuby.targets.flat_map{|_, build| build.products}
desc "clean all built and in-repo installed artifacts"
task :clean do
MRuby.each_target do |build|
rm_rf build.build_dir
rm_f build.products
end
puts "Cleaned up target build directory"
end
desc "clean everything!"
task :deep_clean => %w[clean doc:clean] do
MRuby.each_target do |build|
rm_rf build.gem_clone_dir
end
rm_rf "#{MRUBY_ROOT}/bin"
rm_rf "#{MRUBY_ROOT}/build"
puts "Cleaned up mrbgems build directory"
end
desc "run all pre-commit hooks against all files"
task :check do
sh "prek run --all-files"
end
desc "install the pre-commit hooks"
task :checkinstall do
sh "prek install"
end
desc "check the pre-commit hooks for updates"
task :checkupdate do
sh "prek autoupdate"
end
desc "run all pre-commit hooks against all files with docker-compose"
task :composecheck do
sh "docker-compose -p mruby run test prek run --all-files"
end
desc "build and run all mruby tests with docker-compose"
task :composetest do
sh "docker-compose -p mruby run test"
end

54
vendor/mruby/SECURITY.md vendored Normal file
View file

@ -0,0 +1,54 @@
# Security Policy
## Reporting a Vulnerability
To report a security vulnerability, please email the mruby team at <matz@ruby.or.jp>. We appreciate your efforts to disclose your findings responsibly.
## Scope
mruby is an embeddable Ruby implementation. Its security model is designed for integration into a host application, which is responsible for sandboxing and resource management. This policy defines what we consider a security vulnerability within the mruby interpreter itself.
### High Priority Security Vulnerabilities
We consider the following issues to be **high priority security vulnerabilities**:
- **Remote Code Execution (RCE)**: The ability to execute arbitrary machine code or shell commands from within a Ruby script, beyond the intended execution scope of the script itself.
### Lower Priority: Crashes (Preferably Report as Bugs)
We **accept but deprioritize** the following issues. We recommend reporting them as **bug reports** on our issue tracker rather than security reports:
- **VM Crash on Valid Ruby Code**: Segmentation faults, assertion failures, or other interpreter crashes triggered by syntactically and semantically valid Ruby scripts.
- _Recommendation_: Please report these as bugs on our issue tracker.
- _Rationale_: While we will fix these issues, they typically only result in denial of service (DoS), not arbitrary code execution. They are lower priority than RCE vulnerabilities.
- _Note_: This does not include standard Ruby exceptions like `TypeError` or `ZeroDivisionError`, which are expected behavior.
- _Example_: A segmentation fault when running `[1, 2, 3].map { |x| x * 2 }` is best reported as a bug.
### Out of Scope: Not Considered Security Vulnerabilities
We do **not** consider the following issues to be security vulnerabilities:
- **Resource Exhaustion**: Infinite loops, excessive memory allocation, or high CPU usage originating from a Ruby script.
- _Rationale_: The host application is responsible for implementing resource limits, sandboxing, and execution timeouts. mruby provides the execution engine; the host provides the constraints.
- _Example_: `loop {}` or `"a" * (2**30)` are not vulnerabilities, even if they lead to memory or CPU exhaustion.
- **Crashes from Malformed Bytecode**: Crashes resulting from loading or executing corrupted or intentionally malformed `.mrb` files.
- _Rationale_: mruby's bytecode format is not a security boundary. Applications should only execute bytecode from trusted sources.
- _Example_: A crash discovered by fuzzing `.mrb` files is not considered a vulnerability.
- **Crashes from C API Misuse**: Crashes caused by incorrect usage of mruby's C API from the embedding application.
- _Rationale_: The C API is a trusted interface for developers. The caller is responsible for adhering to the API contract (e.g., not passing `NULL` pointers, managing object lifetimes correctly).
- _Example_: Calling `mrb_funcall()` with an invalid `mrb_state*` pointer is not a vulnerability.
- **Theoretical Undefined Behavior (UB)**: Issues reported by tools like ASAN, UBSan, or Valgrind that do not lead to a demonstrable crash or exploitable behavior in practice.
- _Rationale_: While we strive for clean, well-defined code, our focus is on practical security impact. We prioritize fixing UB that is exploitable over issues that are purely theoretical.
- _Example_: An integer overflow in an intermediate calculation that gets handled correctly before affecting program output or control flow.
- **Warnings on Large Memory Allocations**: Tooling warnings related to large memory allocations that do not result in a crash.
- _Rationale_: mruby is designed to handle `malloc(3)` returning `NULL` on large allocation requests. This is considered graceful error handling, not a vulnerability.
### Summary
- **High Priority Security Reports**: Remote code execution vulnerabilities.
- **Accepted (but preferably as bug reports)**: VM crashes from valid Ruby code.
- **Not Accepted as Security Issues**: Resource exhaustion, malformed bytecode, C API misuse, theoretical undefined behavior, or allocation warnings.

17
vendor/mruby/TODO.md vendored Normal file
View file

@ -0,0 +1,17 @@
# Things to Do in the future
# After mruby 3.4
- parser and code generator independent from `mrb_state` (picoruby?)
- iv/hash entry cache
- method inline caching improvements (cache method lookup results)
- more peephole optimization (if possible)
- built-in profiler (method call tracing, stack profiling, detailed memory analysis)
- improved REPL (mirb) features (syntax highlighting)
- configurable memory pools (per-object-type, memory-constrained devices)
- suspend/resume VM state (serialize/deserialize for power cycling)
- CMake build support (better IDE integration, standard C tooling)
# Things to do (Things we need to consider)
- special variables ($1,$2..)

47
vendor/mruby/appveyor.yml vendored Normal file
View file

@ -0,0 +1,47 @@
version: "{build}"
shallow_clone: true
environment:
matrix:
- job_name: Visual Studio 2022 64-bit
visualcpp: C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat
appveyor_build_worker_image: Visual Studio 2022
- job_name: Visual Studio 2019 64-bit
visualcpp: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat
appveyor_build_worker_image: Visual Studio 2019
- job_name: Visual Studio 2019 32-bit
visualcpp: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars32.bat
appveyor_build_worker_image: Visual Studio 2019
- job_name: Visual Studio 2017 64-bit
visualcpp: C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat
appveyor_build_worker_image: Visual Studio 2017
- job_name: Visual Studio 2017 32-bit
visualcpp: C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars32.bat
appveyor_build_worker_image: Visual Studio 2017
- job_name: Visual Studio 2015 64-bit
visualcpp: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat
appveyor_build_worker_image: Visual Studio 2015
machine: x86_amd64
- job_name: Visual Studio 2015 32-bit
visualcpp: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat
appveyor_build_worker_image: Visual Studio 2015
machine: x86
init:
- call "%visualcpp%" %machine%
# For using RubyInstaller's Ruby 2.6 64-bit
# 2.6 is the highest supported Ruby version across all historical
# Visual Studio AppVeyor images. Ruby 2.7 is only on the 2019 image.
- set PATH=C:\Ruby26-x64\bin;%PATH%
- ruby --version
build_script:
- set MRUBY_CONFIG=ci/msvc
- rake -m test:run:serial

1
vendor/mruby/bin/mirb vendored Symbolic link
View file

@ -0,0 +1 @@
../build/host/bin/mirb

1
vendor/mruby/bin/mrbc vendored Symbolic link
View file

@ -0,0 +1 @@
../build/host/bin/mrbc

1
vendor/mruby/bin/mrdb vendored Symbolic link
View file

@ -0,0 +1 @@
../build/host/bin/mrdb

1
vendor/mruby/bin/mruby vendored Symbolic link
View file

@ -0,0 +1 @@
../build/host/bin/mruby

1
vendor/mruby/bin/mruby-config vendored Symbolic link
View file

@ -0,0 +1 @@
../build/host/bin/mruby-config

1
vendor/mruby/bin/mruby-strip vendored Symbolic link
View file

@ -0,0 +1 @@
../build/host/bin/mruby-strip

9
vendor/mruby/build_config.rb vendored Normal file
View file

@ -0,0 +1,9 @@
# The default build configuration file was moved to `build_config/default.rb`.
#
# Recommended way to customize the build configuration is:
# * copy `default.rb` (or any config file) to a new file (e.g. `myconfig.rb`)
# * edit `myconfig.rb`.
# * `rake MRUBY_CONFIG=/path/to/myconfig.rb` to compile and test.
# * or `rake MRUBY_CONFIG=myconfig` if your configuration file is in the `build_config` directory.
# * (optional) submit your configuration as a pull-request if it's useful for others
raise "The default configuration was moved to `build_config/default.rb`"

72
vendor/mruby/build_config/ArduinoDue.rb vendored Normal file
View file

@ -0,0 +1,72 @@
# Cross Compiling configuration for Arduino Due
# https://arduino.cc/en/Main/ArduinoBoardDue
#
# Requires Arduino IDE >= 1.5
MRuby::CrossBuild.new("ArduinoDue") do |conf|
toolchain :gcc
# Mac OS X, Arduino IDE <= 1.5.6
# ARDUINO_PATH = '/Applications/Arduino.app/Contents/Resources/Java'
# Mac OS X, Arduino IDE >= 1.5.7
# ARDUINO_PATH = '/Applications/Arduino.app/Contents/Java'
# GNU Linux
ARDUINO_PATH = '/opt/arduino'
# Arduino IDE <= 1.5.6
BIN_PATH = "#{ARDUINO_PATH}/hardware/tools/g++_arm_none_eabi/bin"
# Arduino IDE >= 1.5.7
# BIN_PATH = "#{ARDUINO_PATH}/hardware/tools/gcc-arm-none-eabi-4.8.3-2014q1/bin"
SAM_PATH = "#{ARDUINO_PATH}/hardware/arduino/sam"
TARGET_PATH = "#{SAM_PATH}/variants/arduino_due_x"
conf.cc do |cc|
cc.command = "#{BIN_PATH}/arm-none-eabi-gcc"
cc.include_paths << ["#{SAM_PATH}/system/libsam", "#{SAM_PATH}/system/CMSIS/CMSIS/Include/",
"#{SAM_PATH}/system/CMSIS/Device/ATMEL/",
"#{SAM_PATH}/cores/arduino", "#{SAM_PATH}/libraries","#{TARGET_PATH}"]
cc.flags = %w(-g -Os -w -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500
-Dprintf=iprintf -mcpu=cortex-m3 -DF_CPU=84000000L -DARDUINO=156 -DARDUINO_SAM_DUE -DARDUINO_ARCH_SAM
-D__SAM3X8E__ -mthumb -DUSB_PID=0x003e -DUSB_VID=0x2341 -DUSBCON -DUSB_MANUFACTURER="Unknown" -DUSB_PRODUCT="Arduino Due")
cc.compile_options = %Q[%{flags} -o "%{outfile}" -c "%{infile}"]
#configuration for low memory environment
cc.defines << %w(MRB_HEAP_PAGE_SIZE=64)
cc.defines << %w(KHASH_INITIAL_SIZE=8)
cc.defines << %w(MRB_GC_STRESS)
#cc.defines << %w(MRB_NO_STDIO) #if you don't need stdio.
#cc.defines << %w(POOL_PAGE_SIZE=1000) #effective only for use with mruby-eval
end
conf.cxx do |cxx|
cxx.command = conf.cc.command.dup
cxx.include_paths = conf.cc.include_paths.dup
cxx.flags = conf.cc.flags.dup
cxx.flags << %w(-fno-rtti -fno-exceptions)
cxx.defines = conf.cc.defines.dup
cxx.compile_options = conf.cc.compile_options.dup
end
conf.archiver do |archiver|
archiver.command = "#{BIN_PATH}/arm-none-eabi-ar"
archiver.archive_options = 'rcs "%{outfile}" %{objs}'
end
#no executables
conf.bins = []
#do not build executable test
conf.build_mrbtest_lib_only
#disable C++ exception
conf.disable_cxx_exception
#gems from core
conf.gem :core => "mruby-math"
conf.gem :core => "mruby-enum-ext"
#light-weight regular expression
conf.gem :github => "masamitsu-murase/mruby-hs-regexp", :branch => "master"
#Arduino API
#conf.gem :github =>"kyab/mruby-arduino", :branch => "master"
end

View file

@ -0,0 +1,69 @@
# Cross-compiling setup for Intel Edison (poky linux) platform
# Get SDK from here: https://software.intel.com/en-us/iot/hardware/edison/downloads
# REMEMBER to check and update the SDK root in the constant POKY_EDISON_PATH
MRuby::Build.new do |conf|
toolchain :gcc
conf.gembox 'default'
conf.cc.defines = %w(MRB_USE_READLINE)
conf.gembox 'default'
#lightweight regular expression
conf.gem :github => "pbosetti/mruby-hs-regexp", :branch => "master"
end
# Define cross build settings
MRuby::CrossBuild.new('core2-32-poky-linux') do |conf|
toolchain :gcc
# Mac OS X
#
POKY_EDISON_PATH = '/opt/poky-edison/1.7.2'
POKY_EDISON_SYSROOT = "#{POKY_EDISON_PATH}/sysroots/core2-32-poky-linux"
POKY_EDISON_X86_PATH = "#{POKY_EDISON_PATH}/sysroots/i386-pokysdk-darwin"
POKY_EDISON_BIN_PATH = "#{POKY_EDISON_X86_PATH}/usr/bin/i586-poky-linux"
conf.cc do |cc|
cc.command = "#{POKY_EDISON_BIN_PATH}/i586-poky-linux-gcc"
cc.include_paths << ["#{POKY_EDISON_SYSROOT}/usr/include", "#{POKY_EDISON_X86_PATH}/usr/include"]
cc.flags = %w(-m32 -march=core2 -mtune=core2 -msse3 -mfpmath=sse -mstackrealign -fno-omit-frame-pointer)
cc.flags << %w(-O2 -pipe -g -feliminate-unused-debug-types)
cc.flags << "--sysroot=#{POKY_EDISON_SYSROOT}"
cc.compile_options = %Q[%{flags} -o "%{outfile}" -c "%{infile}"]
cc.defines = %w(MRB_USE_READLINE)
end
conf.cxx do |cxx|
cxx.command = "#{POKY_EDISON_BIN_PATH}/i586-poky-linux-g++"
cxx.include_paths = conf.cc.include_paths.dup
cxx.include_paths << ["#{POKY_EDISON_SYSROOT}/usr/include/c++/4.9.1"]
cxx.flags = conf.cc.flags.dup
cxx.defines = conf.cc.defines.dup
cxx.compile_options = conf.cc.compile_options.dup
end
conf.archiver do |archiver|
archiver.command = "#{POKY_EDISON_BIN_PATH}/i586-poky-linux-ar"
archiver.archive_options = 'rcs "%{outfile}" %{objs}'
end
conf.linker do |linker|
linker.command = "#{POKY_EDISON_BIN_PATH}/i586-poky-linux-g++"
linker.flags = %w(-m32 -march=i586)
linker.flags << "--sysroot=#{POKY_EDISON_SYSROOT}"
linker.flags << %w(-O1)
linker.libraries = %w(m pthread)
end
#do not build executable test
conf.build_mrbtest_lib_only
conf.gembox 'default'
#lightweight regular expression
conf.gem :github => "pbosetti/mruby-hs-regexp", :branch => "master"
end

View file

@ -0,0 +1,88 @@
# Cross Compiling configuration for Intel Galileo on Arduino environment
# https://arduino.cc/en/ArduinoCertified/IntelGalileo
#
# Requires Arduino IDE for Intel Galileo
MRuby::CrossBuild.new("Galileo") do |conf|
toolchain :gcc
# Mac OS X
# Assume you renamed Arduino.app to Arduino_Galileo.app
GALILEO_ARDUINO_PATH = '/Applications/Arduino_Galileo.app/Contents/Resources/Java'
# GNU Linux
#ARDUINO_GALILEO_PATH = '/opt/arduino'
GALILEO_BIN_PATH = "#{GALILEO_ARDUINO_PATH}/hardware/tools/x86/i386-pokysdk-darwin/usr/bin/i586-poky-linux-uclibc"
GALILEO_SYSROOT = "#{GALILEO_ARDUINO_PATH}/hardware/tools/x86/i586-poky-linux-uclibc"
GALILEO_X86_PATH = "#{GALILEO_ARDUINO_PATH}/hardware/arduino/x86"
conf.cc do |cc|
cc.command = "#{GALILEO_BIN_PATH}/i586-poky-linux-uclibc-gcc"
cc.include_paths << ["#{GALILEO_X86_PATH}/cores/arduino", "#{GALILEO_X86_PATH}/variants/galileo_fab_d"]
cc.flags = %w(-m32 -march=i586 -c -g -Os -w
-ffunction-sections -fdata-sections -MMD -DARDUINO=153)
cc.flags << "--sysroot=#{GALILEO_SYSROOT}"
cc.compile_options = %Q[%{flags} -o "%{outfile}" -c "%{infile}"]
end
conf.cxx do |cxx|
cxx.command = "#{GALILEO_BIN_PATH}/i586-poky-linux-uclibc-g++"
cxx.include_paths = conf.cc.include_paths.dup
cxx.include_paths << "#{GALILEO_ARDUINO_PATH}/hardware/tools/x86/i586-poky-linux-uclibc/usr/include/c++"
cxx.include_paths << "#{GALILEO_ARDUINO_PATH}/hardware/tools/x86/i586-poky-linux-uclibc/usr/include/c++/i586-poky-linux-uclibc"
cxx.flags = conf.cc.flags.dup
cxx.defines = conf.cc.defines.dup
cxx.compile_options = conf.cc.compile_options.dup
end
conf.archiver do |archiver|
archiver.command = "#{GALILEO_BIN_PATH}/i586-poky-linux-uclibc-ar"
archiver.archive_options = 'rcs "%{outfile}" %{objs}'
end
conf.linker do |linker|
linker.command = "#{GALILEO_BIN_PATH}/i586-poky-linux-uclibc-g++"
linker.flags = %w(-m32 -march=i586)
linker.flags << "--sysroot=#{GALILEO_SYSROOT}"
linker.flags << %w(-Os -Wl,--gc-sections)
linker.libraries = %w(m pthread)
end
#no executables
conf.bins = []
#do not build executable test
conf.build_mrbtest_lib_only
#official mrbgems
conf.gem :core => "mruby-sprintf"
conf.gem :core => "mruby-math"
conf.gem :core => "mruby-time"
conf.gem :core => "mruby-struct"
conf.gem :core => "mruby-enum-ext"
conf.gem :core => "mruby-string-ext"
conf.gem :core => "mruby-numeric-ext"
conf.gem :core => "mruby-array-ext"
conf.gem :core => "mruby-hash-ext"
conf.gem :core => "mruby-range-ext"
conf.gem :core => "mruby-proc-ext"
conf.gem :core => "mruby-symbol-ext"
conf.gem :core => "mruby-random"
conf.gem :core => "mruby-object-ext"
conf.gem :core => "mruby-objectspace"
conf.gem :core => "mruby-fiber"
conf.gem :core => "mruby-toplevel-ext"
#lightweight regular expression
conf.gem :github => "masamitsu-murase/mruby-hs-regexp", :branch => "master"
#Arduino API
#conf.gem :github =>"kyab/mruby-arduino", :branch => "master" do |g|
# g.cxx.include_paths << "#{GALILEO_X86_PATH}/libraries/Wire"
# g.cxx.include_paths << "#{GALILEO_X86_PATH}/libraries/Servo"
#enable unsupported Servo class
# g.cxx.defines << "MRUBY_ARDUINO_GALILEO_ENABLE_SERVO"
#end
end

63
vendor/mruby/build_config/RX630.rb vendored Normal file
View file

@ -0,0 +1,63 @@
# Cross Compiling configuration for RX630
# http://gadget.renesas.com/
#
# Requires gnurx_v14.03
MRuby::CrossBuild.new("RX630") do |conf|
toolchain :gcc
# Linux
BIN_PATH = "/usr/share/gnurx_v14.03_elf-1/bin"
conf.cc do |cc|
cc.command = "#{BIN_PATH}/rx-elf-gcc"
cc.flags = "-Wall -g -O2 -flto -mcpu=rx600 -m64bit-doubles"
cc.compile_options = %Q[%{flags} -o "%{outfile}" -c "%{infile}"]
#configuration for low memory environment
cc.defines << %w(MRB_USE_FLOAT32)
cc.defines << %w(MRB_HEAP_PAGE_SIZE=64)
cc.defines << %w(KHASH_INITIAL_SIZE=8)
cc.defines << %w(MRB_GC_STRESS)
cc.defines << %w(MRB_NO_STDIO) #if you don't need stdio.
#cc.defines << %w(POOL_PAGE_SIZE=1000) #effective only for use with mruby-eval
end
conf.cxx do |cxx|
cxx.command = conf.cc.command.dup
cxx.include_paths = conf.cc.include_paths.dup
cxx.flags = conf.cc.flags.dup
cxx.defines = conf.cc.defines.dup
cxx.compile_options = conf.cc.compile_options.dup
end
conf.linker do |linker|
linker.command="#{BIN_PATH}/rx-elf-ld"
end
conf.archiver do |archiver|
archiver.command = "#{BIN_PATH}/rx-elf-ar"
archiver.archive_options = 'rcs "%{outfile}" %{objs}'
end
#no executables
conf.bins = []
#do not build executable test
conf.build_mrbtest_lib_only
#disable C++ exception
conf.disable_cxx_exception
#gems from core
conf.gem :core => "mruby-sprintf"
conf.gem :core => "mruby-math"
conf.gem :core => "mruby-enum-ext"
conf.gem :core => "mruby-numeric-ext"
#light-weight regular expression
#conf.gem :github => "masamitsu-murase/mruby-hs-regexp", :branch => "master"
#Arduino API
#conf.gem :github =>"kyab/mruby-arduino", :branch => "master"
end

View file

@ -0,0 +1,11 @@
# Requires Android NDK r13 or later.
MRuby::CrossBuild.new('android-arm64-v8a') do |conf|
params = {
:arch => 'arm64-v8a',
:sdk_version => 33,
:toolchain => :clang
}
toolchain :android, params
conf.gembox 'default'
end

View file

@ -0,0 +1,13 @@
# Requires Android NDK r13 or later.
MRuby::CrossBuild.new('android-armeabi-v7a-neon-hard') do |conf|
params = {
:arch => 'armeabi-v7a',
:mfpu => 'neon',
:mfloat_abi => 'hard',
:sdk_version => 33,
:toolchain => :clang
}
toolchain :android, params
conf.gembox 'default'
end

11
vendor/mruby/build_config/bench.rb vendored Normal file
View file

@ -0,0 +1,11 @@
MRuby::Build.new('bench') do |conf|
# Gets set by the VS command prompts.
if ENV['VisualStudioVersion'] || ENV['VSINSTALLDIR']
toolchain :visualcpp
else
toolchain :gcc
conf.cc.flags << '-O3'
end
conf.gembox 'default'
end

19
vendor/mruby/build_config/boxing.rb vendored Normal file
View file

@ -0,0 +1,19 @@
boxings = %w[no word nan]
bits = [64, 32]
ints = [64, 32]
boxings.product(bits, ints) do |boxing, bit, int|
MRuby::Build.new("boxing-#{boxing}-m#{bit}-i#{int}") do |conf|
conf.toolchain :gcc
conf.gembox 'full-core'
conf.compilers.each do |c|
c.defines << "MRB_#{boxing.upcase}_BOXING"
c.defines << "MRB_INT#{int}"
c.flags << "-m#{bit}"
end
conf.linker.flags << "-m#{bit}"
conf.enable_debug
conf.enable_test
conf.enable_bintest
end
end

View file

@ -0,0 +1,68 @@
# Cross Compiling configuration for Digilent chipKIT Max32
# https://www.digilentinc.com/Products/Detail.cfm?Prod=CHIPKIT-MAX32
#
# Requires MPIDE (https://github.com/chipKIT32/chipKIT32-MAX)
#
# This configuration is based on @kyab's version
# http://d.hatena.ne.jp/kyab/20130201
MRuby::CrossBuild.new("chipKITMax32") do |conf|
toolchain :gcc
# Mac OS X
# MPIDE_PATH = '/Applications/Mpide.app/Contents/Resources/Java'
# GNU Linux
MPIDE_PATH = '/opt/mpide-0023-linux-20120903'
PIC32_PATH = "#{MPIDE_PATH}/hardware/pic32"
conf.cc do |cc|
cc.command = "#{PIC32_PATH}/compiler/pic32-tools/bin/pic32-gcc"
cc.include_paths << ["#{PIC32_PATH}/cores/pic32",
"#{PIC32_PATH}/variants/Max32",
"#{PIC32_PATH}/libraries"]
cc.flags = %w(-O2 -mno-smart-io -w -ffunction-sections -fdata-sections -g -mdebugger -Wcast-align
-fno-short-double -mprocessor=32MX795F512L -DF_CPU=80000000L -DARDUINO=23 -D_BOARD_MEGA_
-DMPIDEVER=0x01000202 -DMPIDE=23)
cc.compile_options = %Q[%{flags} -o "%{outfile}" -c "%{infile}"]
#configuration for low memory environment
cc.defines << %w(MRB_HEAP_PAGE_SIZE=64)
cc.defines << %w(KHASH_INITIAL_SIZE=8)
cc.defines << %w(MRB_GC_STRESS)
#cc.defines << %w(MRB_NO_STDIO) #if you don't need stdio.
#cc.defines << %w(POOL_PAGE_SIZE=1000) #effective only for use with mruby-eval
end
conf.cxx do |cxx|
cxx.command = conf.cc.command.dup
cxx.include_paths = conf.cc.include_paths.dup
cxx.flags = conf.cc.flags.dup
cxx.defines = conf.cc.defines.dup
cxx.compile_options = conf.cc.compile_options.dup
end
conf.archiver do |archiver|
archiver.command = "#{PIC32_PATH}/compiler/pic32-tools/bin/pic32-ar"
archiver.archive_options = 'rcs "%{outfile}" %{objs}'
end
#no executables
conf.bins = []
#do not build test executable
conf.build_mrbtest_lib_only
#disable C++ exception
conf.disable_cxx_exception
#gems from core
conf.gem :core => "mruby-math"
conf.gem :core => "mruby-enum-ext"
#light-weight regular expression
conf.gem :github => "masamitsu-murase/mruby-hs-regexp", :branch => "master"
#Arduino API
#conf.gem :github =>"kyab/mruby-arduino", :branch => "master"
end

View file

@ -0,0 +1,40 @@
STDOUT.sync = STDERR.sync = true unless Rake.application.options.always_multitask
MRuby::Build.new('full-debug') do |conf|
conf.toolchain
conf.enable_debug
# include all core GEMs
conf.gembox 'full-core'
conf.cc.defines += %w(MRB_GC_STRESS MRB_USE_DEBUG_HOOK)
conf.enable_test
end
MRuby::Build.new do |conf|
conf.toolchain
# include all core GEMs
conf.gembox 'full-core'
conf.gem :core => 'mruby-bin-debugger'
conf.compilers.each do |c|
c.defines += %w(MRB_GC_FIXED_ARENA)
end
conf.enable_bintest
conf.enable_test
end
MRuby::Build.new('cxx_abi') do |conf|
conf.toolchain
conf.gembox 'full-core'
conf.cc.flags += %w(-fpermissive -std=gnu++03)
conf.compilers.each do |c|
c.defines += %w(MRB_GC_FIXED_ARENA)
end
conf.enable_test
conf.enable_cxx_abi
conf.build_mrbc_exec
end

20
vendor/mruby/build_config/ci/msvc.rb vendored Normal file
View file

@ -0,0 +1,20 @@
STDOUT.sync = STDERR.sync = true unless Rake.application.options.always_multitask
def setup_option(conf)
conf.cc.compile_options.sub!(%r{/Zi }, "") unless ENV['CFLAGS']
conf.cxx.compile_options.sub!(%r{/Zi }, "") unless ENV['CFLAGS'] || ENV['CXXFLAGS']
conf.linker.flags << "/DEBUG:NONE" unless ENV['LDFLAGS']
end
MRuby::Build.new do |conf|
conf.toolchain :visualcpp
# include all core GEMs
conf.gembox 'full-core'
conf.compilers.each do |c|
c.defines += %w(MRB_GC_FIXED_ARENA)
end
setup_option(conf)
conf.enable_bintest
conf.enable_test
end

11
vendor/mruby/build_config/clang-asan.rb vendored Normal file
View file

@ -0,0 +1,11 @@
MRuby::Build.new do |conf|
conf.toolchain :clang
# include the GEM box
conf.gembox 'full-core'
# Turn on `enable_debug` for better debugging
conf.enable_sanitizer "address,undefined"
conf.enable_debug
conf.enable_bintest
conf.enable_test
end

View file

@ -0,0 +1,86 @@
# Cosmopolitan Libc build configuration for mruby
# https://github.com/jart/cosmopolitan
#
# Produces Actually Portable Executables (APE) - single binaries that run on:
# - Linux (x86_64, ARM64)
# - macOS (x86_64, ARM64)
# - Windows (x86_64)
# - FreeBSD (x86_64)
# - OpenBSD (x86_64)
# - NetBSD (x86_64)
#
# Requirements:
# Download cosmocc toolchain from https://cosmo.zip/pub/cosmocc/
#
# Usage:
# COSMO_ROOT=/path/to/cosmocc rake MRUBY_CONFIG=cosmopolitan
#
# The resulting binaries in bin/ will have .com extension and run on all
# supported platforms without recompilation.
COSMO_ROOT = ENV['COSMO_ROOT']
unless COSMO_ROOT && File.directory?(COSMO_ROOT)
msg = <<~MSG
Cosmopolitan toolchain not found.
Please set COSMO_ROOT environment variable to the cosmocc directory:
mkdir -p ~/cosmo && cd ~/cosmo
wget https://cosmo.zip/pub/cosmocc/cosmocc.zip
unzip cosmocc.zip
export COSMO_ROOT=~/cosmo
Then run:
COSMO_ROOT=~/cosmo rake MRUBY_CONFIG=cosmopolitan
MSG
raise msg
end
MRuby::Build.new do |conf|
# C compiler
conf.cc do |cc|
cc.command = "#{COSMO_ROOT}/bin/cosmocc"
cc.flags = %w[-Os -fno-omit-frame-pointer]
end
# C++ compiler
conf.cxx do |cxx|
cxx.command = "#{COSMO_ROOT}/bin/cosmoc++"
cxx.flags = conf.cc.flags.dup
end
# Linker
conf.linker do |linker|
linker.command = "#{COSMO_ROOT}/bin/cosmocc"
linker.flags = %w[-static]
end
# Archiver
conf.archiver do |archiver|
archiver.command = "#{COSMO_ROOT}/bin/cosmoar"
end
# APE binaries use .com extension
conf.exts.executable = '.com'
# Cosmopolitan provides POSIX compatibility, explicitly select POSIX HALs
conf.gem core: 'hal-posix-io'
conf.gem core: 'hal-posix-socket'
conf.gem core: 'hal-posix-dir'
# Standard library
conf.gembox 'stdlib'
conf.gembox 'stdlib-ext'
conf.gembox 'stdlib-io' # Includes mruby-io, mruby-socket, mruby-dir
conf.gembox 'math'
conf.gembox 'metaprog'
# Binary tools
# Note: mruby-bin-config is a shell script and incompatible with .com extension
conf.gem core: 'mruby-bin-mrbc'
conf.gem core: 'mruby-bin-mruby'
conf.gem core: 'mruby-bin-strip'
conf.gem core: 'mruby-bin-mirb'
conf.gem core: 'mruby-bin-debugger'
end

View file

@ -0,0 +1,14 @@
# Define cross build settings
MRuby::CrossBuild.new('cross-32bit') do |conf|
conf.toolchain :gcc
conf.cc.flags << "-m32"
conf.linker.flags << "-m32"
# conf.build_mrbtest_lib_only
conf.gem :core => "mruby-bin-mruby"
conf.gem "#{MRUBY_ROOT}/examples/mrbgems/c_and_ruby_extension_example"
conf.test_runner.command = 'env'
end

View file

@ -0,0 +1,90 @@
# Cross-compile using MinGW and test using Wine.
#
# Steps:
#
# 1. Install MinGW; 64-bit target seems to work best.
#
# 2. Install Wine.
#
# 3. Run command:
#
# wine cmd /c echo "Hello world"'
#
# This will confirm that Wine works and will trigger standard
# Wine setup, which is slow.
#
# 4. Confirm that drive 'z:' is mapped to your root filesystem.
# (This is supposed to be a default but it helps to
# double-check.) To confirm, run:
#
# wine cmd /c dir 'z:\\'
#
# This should give you a DOS-style equivalent of 'ls /'. If not,
# you'll need to fix that with winecfg or by adding a symlink to
# '~/.wine/dosdevices'.
#
# 5. You will likely need to tweak the settings below to work with
# your configuration unless it is exactly like one of the platforms
# I've tested on (Ubuntu 20.04 or macOS using brew.)
#
# 6. Run the build command:
#
# MRUBY_CONFIG=build_config/cross-mingw-winetest.rb rake test
#
# If all goes well, you should now have Windows executables and a
# set of passing tests.
#
#
# Caveats:
#
# 1. This works by using a helper script that rewrites test output
# to make it look *nix-like and then handing it back to the test
# cases. Some of the existing tests were (slightly) modified to
# make this easier but only for the 'full-core' gembox. Other
# gems' bintests may or may not work with the helper script and
# may or may not be fixable by extending the script.
#
# 2. MinGW and Wine are both complex and not very consistent so you
# will likely need to do some fiddling to get things to work.
#
# 3. This script assumes you are running it on a *nix-style OS.
#
# 4. I recommend building 64-bit targets only. Building a 32-bit
# Windows binary with i686-w64-mingw32 seems to work (at least,
# it did for me) but the resulting executable failed a number of
# unit tests due to small errors in some floating-point
# operations. It's unclear if this indicates more serious problems.
#
MRuby::CrossBuild.new("cross-mingw-winetest") do |conf|
conf.toolchain :gcc
conf.host_target = "x86_64-w64-mingw32"
# Ubuntu 20
conf.cc.command = "#{conf.host_target}-gcc-posix"
# macOS+Wine from brew
#conf.cc.command = "#{conf.host_target}-gcc"
conf.linker.command = conf.cc.command
conf.archiver.command = "#{conf.host_target}-gcc-ar"
conf.exts.executable = ".exe"
# By default, we compile as static as possible to remove runtime
# MinGW dependencies; they are probably fixable but it gets
# complicated.
conf.cc.flags = ['-static']
conf.linker.flags += ['-static']
conf.test_runner do |t|
thisdir = File.absolute_path( File.dirname(__FILE__) )
t.command = File.join(thisdir, * %w{ helpers wine_runner.rb})
end
conf.gembox "full-core"
conf.enable_bintest
conf.enable_test
end

View file

@ -0,0 +1,14 @@
#
# Ubuntu 20.04 requires at least `gcc-mingw-w64-x86-64` package as a
# cross compiler.
#
MRuby::CrossBuild.new("cross-mingw") do |conf|
conf.toolchain :gcc
conf.host_target = "x86_64-w64-mingw32" # required for `for_windows?` used by `mruby-socket` gem
conf.cc.command = "#{conf.host_target}-gcc-posix"
conf.linker.command = conf.cc.command
conf.archiver.command = "#{conf.host_target}-gcc-ar"
conf.exts.executable = ".exe"
conf.gembox "default"
end

83
vendor/mruby/build_config/default.rb vendored Normal file
View file

@ -0,0 +1,83 @@
MRuby::Build.new do |conf|
# load specific toolchain settings
conf.toolchain
# Use mrbgems
# conf.gem 'examples/mrbgems/ruby_extension_example'
# conf.gem 'examples/mrbgems/c_extension_example' do |g|
# g.cc.flags << '-g' # append cflags in this gem
# end
# conf.gem 'examples/mrbgems/c_and_ruby_extension_example'
# conf.gem :core => 'mruby-eval'
# conf.gem :mgem => 'mruby-onig-regexp'
# conf.gem :github => 'mattn/mruby-onig-regexp'
# conf.gem :git => 'git@github.com:mattn/mruby-onig-regexp.git', :branch => 'master', :options => '-v'
# include the GEM box
conf.gembox 'default'
# C compiler settings
# conf.cc do |cc|
# cc.command = ENV['CC'] || 'gcc'
# cc.flags = [ENV['CFLAGS'] || %w()]
# cc.include_paths = ["#{root}/include"]
# cc.defines = %w()
# cc.option_include_path = %q[-I"%s"]
# cc.option_define = '-D%s'
# cc.compile_options = %Q[%{flags} -MMD -o "%{outfile}" -c "%{infile}"]
# end
# mrbc settings
# conf.mrbc do |mrbc|
# mrbc.compile_options = "-g -B%{funcname} -o-" # The -g option is required for line numbers
# end
# Linker settings
# conf.linker do |linker|
# linker.command = ENV['LD'] || 'gcc'
# linker.flags = [ENV['LDFLAGS'] || []]
# linker.flags_before_libraries = []
# linker.libraries = %w()
# linker.flags_after_libraries = []
# linker.library_paths = []
# linker.option_library = '-l%s'
# linker.option_library_path = '-L%s'
# linker.link_options = %Q[%{flags} -o "%{outfile}" %{objs} %{libs}]
# end
# Archiver settings
# conf.archiver do |archiver|
# archiver.command = ENV['AR'] || 'ar'
# archiver.archive_options = 'rs "%{outfile}" %{objs}'
# end
# Parser generator settings
# conf.yacc do |yacc|
# yacc.command = ENV['YACC'] || 'bison'
# yacc.compile_options = %q[-o "%{outfile}" "%{infile}"]
# end
# gperf settings
# conf.gperf do |gperf|
# gperf.command = 'gperf'
# gperf.compile_options = %q[-L ANSI-C -C -j1 -i 1 -o -t -N mrb_reserved_word -k"1,3,$" "%{infile}" > "%{outfile}"]
# end
# file extensions
# conf.exts do |exts|
# exts.object = '.o'
# exts.executable = '' # '.exe' if Windows
# exts.library = '.a'
# end
# file separator
# conf.file_separator = '/'
# change library directory name from the default "lib" if necessary
# conf.libdir_name = 'lib64'
# Turn on `enable_debug` for better debugging
# conf.enable_debug
conf.enable_bintest
conf.enable_test
end

View file

@ -0,0 +1,81 @@
# Cross Compiling configuration for the Sega Dreamcast
# https://dreamcast.wiki/Using_Ruby_for_Sega_Dreamcast_development
#
# Requires KallistiOS (KOS)
# http://gamedev.allusion.net/softprj/kos/
#
# This configuration has been improved to be used as KallistiOS Port (kos-ports)
# Updated: 2025-07-31
#
# Tested on GNU/Linux, macOS and Windows (MinGW-w64/MSYS2, Cygwin, DreamSDK)
# DreamSDK is based on both MinGW/MSYS and MinGW-w64/MSYS2: https://dreamsdk.org/
#
# Install mruby for Sega Dreamcast using the "mruby" kos-port.
# See: https://github.com/kallistios/kallistios
#
# If you want to see examples, check the /examples/dreamcast/mruby directory
# in the KallistiOS repository.
#
MRuby::CrossBuild.new("dreamcast") do |conf|
toolchain :gcc
# Getting critical environment variables
KOS_BASE = ENV["KOS_BASE"]
KOS_CC_BASE = ENV["KOS_CC_BASE"]
# Check environment variables
if KOS_BASE.to_s.empty?
raise "Error: KallistiOS is required; KOS_BASE need to be declared; Stop."
end
# Root directory for KallistiOS wrappers
# This will handle specific DreamSDK wrappers if needed
KOS_WRAPPERS_BASE = if ENV["ENVIRONMENT_NAME"] == "DreamSDK" && ENV["RAKE_AVAILABLE"] == "0"
"#{KOS_CC_BASE}/bin"
else
"#{KOS_BASE}/utils/build_wrappers"
end
# C compiler
conf.cc do |cc|
cc.command = "#{KOS_WRAPPERS_BASE}/kos-cc"
end
# C++ compiler
conf.cxx do |cxx|
cxx.command = "#{KOS_WRAPPERS_BASE}/kos-c++"
end
# Linker
conf.linker do |linker|
linker.command = "#{KOS_WRAPPERS_BASE}/kos-ld"
end
# Archiver
conf.archiver do |archiver|
archiver.command = "#{KOS_WRAPPERS_BASE}/kos-ar"
end
# No executables needed for KallistiOS
conf.bins = []
# Do not build test binaries
conf.build_mrbtest_lib_only
# Gemboxes
conf.gembox "default-no-stdio"
conf.gembox "stdlib-ext"
conf.gembox "metaprog"
# Additional Gems
# Currently unsupported on KallistiOS: "mruby-io", "mruby-dir", "mruby-socket"
conf.gem :core => "mruby-binding"
conf.gem :core => "mruby-catch"
conf.gem :core => "mruby-enum-chain"
conf.gem :core => "mruby-errno"
conf.gem :core => "mruby-error"
conf.gem :core => "mruby-exit"
conf.gem :core => "mruby-os-memsize"
conf.gem :core => "mruby-proc-binding"
conf.gem :core => "mruby-sleep"
end

View file

@ -0,0 +1,12 @@
# Make sure to add these compile options:
# build/emscripten-cxx/host-bin/mruby-config --cxxflags
#
# Make sure to add these link options:
# build/emscripten-cxx/host-bin/mruby-config --ldflags --libs
MRuby::CrossBuild.new('emscripten-cxx') do |conf|
conf.toolchain :emscripten
conf.gembox 'default'
conf.enable_cxx_abi
end

10
vendor/mruby/build_config/emscripten.rb vendored Normal file
View file

@ -0,0 +1,10 @@
# Make sure to add these compile options:
# build/emscripten/host-bin/mruby-config --cflags
#
# Make sure to add these link options:
# build/emscripten/host-bin/mruby-config --ldflags --libs
MRuby::CrossBuild.new('emscripten') do |conf|
conf.toolchain :emscripten
conf.gembox 'default'
end

View file

@ -0,0 +1,72 @@
# Cross Compiling configuration for the Nintendo GameBoyAdvance.
# This configuration requires devkitARM
# https://devkitpro.org/wiki/Getting_Started/devkitARM
#
# Tested only on GNU/Linux
#
MRuby::CrossBuild.new("gameboyadvance") do |conf|
toolchain :gcc
DEVKITPRO_PATH = "/opt/devkitpro"
BIN_PATH = "#{DEVKITPRO_PATH}/devkitARM/bin"
# C compiler
conf.cc do |cc|
cc.command = "#{BIN_PATH}/arm-none-eabi-gcc"
cc.flags << ["-mthumb-interwork", "-mthumb", "-O2"]
cc.compile_options = %(%{flags} -o "%{outfile}" -c "%{infile}")
end
# C++ compiler
conf.cxx do |cxx|
cxx.command = "#{BIN_PATH}/arm-none-eabi-g++"
cxx.include_paths = conf.cc.include_paths.dup
cxx.flags = conf.cc.flags.dup
cxx.flags << %w[-fno-rtti -fno-exceptions]
cxx.defines = conf.cc.defines.dup
cxx.compile_options = conf.cc.compile_options.dup
end
# Linker
conf.linker do |linker|
linker.command = "#{BIN_PATH}/arm-none-eabi-gcc"
linker.flags << ["-mthumb-interwork", "-mthumb", "-specs=gba.specs"]
end
# No executables
conf.bins = []
# Do not build executable test
conf.build_mrbtest_lib_only
# Disable C++ exception
conf.disable_cxx_exception
# Gems from core
# removing mruby-io
conf.gem core: "mruby-metaprog"
conf.gem core: "mruby-pack"
conf.gem core: "mruby-sprintf"
conf.gem core: "mruby-math"
conf.gem core: "mruby-time"
conf.gem core: "mruby-struct"
conf.gem core: "mruby-compar-ext"
conf.gem core: "mruby-enum-ext"
conf.gem core: "mruby-string-ext"
conf.gem core: "mruby-numeric-ext"
conf.gem core: "mruby-array-ext"
conf.gem core: "mruby-hash-ext"
conf.gem core: "mruby-range-ext"
conf.gem core: "mruby-proc-ext"
conf.gem core: "mruby-symbol-ext"
conf.gem core: "mruby-random"
conf.gem core: "mruby-object-ext"
conf.gem core: "mruby-objectspace"
conf.gem core: "mruby-fiber"
conf.gem core: "mruby-enumerator"
conf.gem core: "mruby-enum-lazy"
conf.gem core: "mruby-toplevel-ext"
conf.gem core: "mruby-kernel-ext"
conf.gem core: "mruby-class-ext"
conf.gem core: "mruby-compiler"
end

View file

@ -0,0 +1,71 @@
#!/usr/bin/env ruby
# Wrapper for running tests for cross-compiled Windows builds in Wine.
require 'open3'
DOSROOT = 'z:'
# Rewrite test output to replace DOS-isms with Unix-isms.
def clean(output, stderr = false)
ends_with_newline = !!(output =~ /\n$/)
executable = ARGV[0].gsub(/\.exe\z/i, '')
# Fix line-ends
output = output.gsub(/\r\n/, "\n")
# Strip out Wine messages
results = output.split(/\n/).map do |line|
# Fix file paths
if line =~ /#{DOSROOT}\\/i
line.gsub!(/#{DOSROOT}([^:]*)/i) { |path|
path.gsub!(/^#{DOSROOT}/i, '')
path.gsub!(%r{\\}, '/')
path
}
end
# strip '.exe' off the end of the executable's name if needed
line.gsub!(/(#{Regexp.escape executable})\.exe/i, '\1')
line
end
result_text = results.join("\n")
result_text += "\n" if ends_with_newline
result_text
end
def main
if ARGV.empty? || ARGV[0] =~ /^- (-?) (\?|help|h) $/x
puts "#{$0} <command-line>"
exit 0
end
# For simplicity, just read all of stdin into memory and pass that
# as an argument when invoking wine. (Skipped if STDIN was not
# redirected.)
if !STDIN.tty?
input = STDIN.read
else
input = ""
end
# Disable all Wine messages so they don't interfere with the output
ENV['WINEDEBUG'] = 'err-all,warn-all,fixme-all,trace-all'
# Run the program in wine and capture the output
output, errormsg, status = Open3.capture3('wine', *ARGV, :stdin_data => input)
# Clean and print the results.
STDOUT.write clean(output)
STDERR.write clean(errormsg)
exit(status.exitstatus)
end
main()

12
vendor/mruby/build_config/host-cxx.rb vendored Normal file
View file

@ -0,0 +1,12 @@
MRuby::Build.new do |conf|
conf.toolchain
# include the default GEMs
conf.gembox 'default'
# C compiler settings
conf.cc.defines = %w(MRB_USE_DEBUG_HOOK)
conf.enable_debug
conf.enable_cxx_abi
conf.enable_test
end

20
vendor/mruby/build_config/host-debug.rb vendored Normal file
View file

@ -0,0 +1,20 @@
MRuby::Build.new('host') do |conf|
# load specific toolchain settings
conf.toolchain
conf.enable_debug
# include the default GEMs
conf.gembox 'full-core'
# C compiler settings
conf.cc.defines = %w(MRB_USE_DEBUG_HOOK MRB_NO_BOXING)
# Generate mruby debugger command (require mruby-eval)
conf.gem :core => "mruby-bin-debugger"
# test
conf.enable_test
# bintest
conf.enable_bintest
end

14
vendor/mruby/build_config/host-f32.rb vendored Normal file
View file

@ -0,0 +1,14 @@
MRuby::Build.new do |conf|
# load specific toolchain settings
toolchain :gcc
# include the GEM box
conf.gembox 'full-core'
conf.cc.defines << 'MRB_USE_FLOAT32'
# Turn on `enable_debug` for better debugging
conf.enable_debug
conf.enable_test
conf.enable_bintest
end

14
vendor/mruby/build_config/host-gprof.rb vendored Normal file
View file

@ -0,0 +1,14 @@
MRuby::Build.new do |conf|
# load specific toolchain settings
toolchain :gcc
# include the GEM box
conf.gembox 'full-core'
conf.cc.flags << '-pg'
conf.linker.flags << '-pg'
# Turn on `enable_debug` for better debugging
conf.enable_debug
conf.enable_test
end

View file

@ -0,0 +1,16 @@
MRuby::Build.new do |conf|
# load specific toolchain settings
toolchain :gcc
# include the GEM box
conf.gembox 'full-core'
conf.cc.flags << '-m32'
conf.cc.defines << 'MRB_USE_FLOAT32'
conf.linker.flags << '-m32'
# Turn on `enable_debug` for better debugging
conf.enable_debug
conf.enable_test
conf.enable_bintest
end

15
vendor/mruby/build_config/host-m32.rb vendored Normal file
View file

@ -0,0 +1,15 @@
MRuby::Build.new do |conf|
# load specific toolchain settings
toolchain :gcc
# include the GEM box
conf.gembox 'full-core'
conf.cc.flags << '-m32'
conf.linker.flags << '-m32'
# Turn on `enable_debug` for better debugging
conf.enable_debug
conf.enable_test
conf.enable_bintest
end

View file

@ -0,0 +1,22 @@
MRuby::Build.new do |conf|
# load specific toolchain settings
toolchain :gcc
# include the GEM box
conf.gembox "stdlib"
conf.gembox "stdlib-ext"
conf.gembox "stdlib-io"
conf.gembox "metaprog"
conf.gem :core => 'mruby-bin-mruby'
conf.gem :core => 'mruby-bin-mirb'
# Add configuration
conf.compilers.each do |c|
c.defines << "MRB_NO_FLOAT"
end
conf.enable_debug
conf.enable_test
conf.enable_bintest
end

View file

@ -0,0 +1,36 @@
# NOTE: Currently, this configuration file does not support VisualC++!
# Your help is needed!
MRuby::Build.new do |conf|
# load specific toolchain settings
conf.toolchain
# include the GEM box
conf.gembox 'default'
# C compiler settings
conf.compilers.each do |cc|
cc.flags << '-fPIC'
end
conf.archiver do |archiver|
archiver.command = cc.command
archiver.archive_options = '-shared -o %{outfile} %{objs}'
end
# file extensions
conf.exts do |exts|
exts.library = '.so'
end
# file separator
# conf.file_separator = '/'
# enable this if better compatibility with C++ is desired
#conf.enable_cxx_exception
# Turn on `enable_debug` for better debugging
conf.enable_debug
conf.enable_bintest
conf.enable_test
end

View file

@ -0,0 +1,76 @@
# Cross Compiling configuration for MS-DOS
#
# Requires DJGPP cross-compiler, see
# https://github.com/andrewwutw/build-djgpp/releases
MRuby::CrossBuild.new("i586-pc-msdosdjgpp") do |conf|
toolchain :gcc
# If DJGPP is not in the PATH, set this to the bin directory
DJGPP_PATH = nil
GCC = 'i586-pc-msdosdjgpp-gcc'
GXX = 'i586-pc-msdosdjgpp-g++'
AR = 'i586-pc-msdosdjgpp-ar'
conf.cc do |cc|
cc.command = DJGPP_PATH ? File.join(DJGPP_PATH, GCC) : GCC
cc.defines << 'MRB_NO_IO_PREAD_PWRITE'
cc.defines << 'MRB_UTF8_STRING'
end
conf.cxx do |cxx|
cxx.command = DJGPP_PATH ? File.join(DJGPP_PATH, GXX) : GXX
cxx.defines << 'MRB_NO_IO_PREAD_PWRITE'
cxx.defines << 'MRB_UTF8_STRING'
end
conf.linker do |linker|
linker.command = DJGPP_PATH ? File.join(DJGPP_PATH, GXX) : GXX
linker.libraries = %w(m)
end
conf.archiver do |archiver|
archiver.command = DJGPP_PATH ? File.join(DJGPP_PATH, AR) : AR
end
# All provided gems that can be reasonably made to compile:
# default.gembox, minus mruby-socket and replacing mruby-cmath with mruby-cmath-alt
conf.gembox "stdlib"
conf.gembox "stdlib-ext"
conf.gem :core => 'mruby-io' # stdlib-io.gembox <- default.gembox
# No socket support in DJGPP
# conf.gem :core => 'mruby-socket' # stdlib-io.gembox <- default.gembox
conf.gem :core => 'mruby-errno' # stdlib-io.gembox <- default.gembox
conf.gem :core => 'mruby-dir' # stdlib-io.gembox <- default.gembox
conf.gem :core => 'mruby-bigint' # math.gembox <- default.gembox
conf.gem :core => 'mruby-complex' # math.gembox <- default.gembox
conf.gem :core => 'mruby-math' # math.gembox <- default.gembox
conf.gem :core => 'mruby-rational' # math.gembox <- default.gembox
# Alternative implementation of cmath, not requiring <complex.h>
# conf.gem :github => 'chasonr/mruby-cmath-alt' # math.gembox <- default.gembox
conf.gembox "metaprog"
conf.gem :core => 'mruby-bin-mrbc' # default.gembox
conf.gem :core => 'mruby-bin-debugger' # default.gembox
conf.gem :core => 'mruby-bin-mirb' # default.gembox
conf.gem :core => 'mruby-bin-mruby' # default.gembox
conf.gem :core => 'mruby-bin-strip' # default.gembox
conf.gem :core => 'mruby-bin-config' # default.gembox
# Other compilable gems
conf.gem :core => 'mruby-binding'
conf.gem :core => 'mruby-catch'
conf.gem :core => 'mruby-enum-chain'
conf.gem :core => 'mruby-error'
conf.gem :core => 'mruby-exit'
conf.gem :core => 'mruby-os-memsize'
conf.gem :core => 'mruby-proc-binding'
conf.gem :core => 'mruby-sleep'
# For Onigmo regular expression support
conf.gem :github => 'mattn/mruby-onig-regexp'
end

View file

@ -0,0 +1,106 @@
# Cross Compiling configuration for Luckfox Pico embedded SBC.
#
# To build on Ubuntu x86_64: rake MRUBY_CONFIG=build_config/luckfox_pico.rb
# Uses Buildroot SDK for this board. Binaries run on the corresponding Linux image.
# Requires: https://github.com/LuckfoxTECH/luckfox-pico
#
# NOTE: default config includes all standard mrbgems, EXCEPT: mruby-cmath
#
MRuby::CrossBuild.new("luckfox_pico") do |conf|
# Clone the luckfox-pico repo above next to (same directory level) as mruby.
SDK_BASE = File.realpath(File.expand_path("../../../", File.expand_path(__FILE__)) + "/luckfox-pico")
TOOLCHAIN_BASE = "#{SDK_BASE}/tools/linux/toolchain/arm-rockchip830-linux-uclibcgnueabihf"
SYSROOT = "#{TOOLCHAIN_BASE}/arm-rockchip830-linux-uclibcgnueabihf/sysroot"
toolchain :gcc
# C compiler settings
conf.cc do |cc|
cc.command = "#{TOOLCHAIN_BASE}/bin/arm-rockchip830-linux-uclibcgnueabihf-gcc"
cc.include_paths << "#{TOOLCHAIN_BASE}/lib/gcc/arm-rockchip830-linux-uclibcgnueabihf/8.3.0/include"
cc.include_paths << "#{TOOLCHAIN_BASE}/lib/gcc/arm-rockchip830-linux-uclibcgnueabihf/8.3.0/include-fixed"
cc.include_paths << "#{TOOLCHAIN_BASE}/arm-rockchip830-linux-uclibcgnueabihf/include/c++/8.3.0/arm-rockchip830-linux-uclibcgnueabihf"
cc.include_paths << "#{SYSROOT}/usr/include"
# Flags taken from the SDK's Makefile
cc.flags << ["-march=armv7-a", "-mfpu=neon", "-mfloat-abi=hard"]
cc.flags << ["-D_LARGEFILE_SOURCE", "-D_LARGEFILE64_SOURCE", "-D_FILE_OFFSET_BITS=64", "-ffunction-sections", "-fdata-sections"]
cc.flags << ["-O2", "-fPIC"]
cc.flags << ["-Wl,--copy-dt-needed-entries", "-Wl,-lc,-lgcc_s"]
end
# Linker settings
conf.linker do |linker|
linker.command = cc.command
linker.library_paths << "#{TOOLCHAIN_BASE}/arm-rockchip830-linux-uclibcgnueabihf/lib"
linker.flags = cc.flags
end
# Archiver settings
conf.archiver do |archiver|
archiver.command = "#{TOOLCHAIN_BASE}/bin/arm-rockchip830-linux-uclibcgnueabihf-ar"
end
# Do not build executable test
conf.build_mrbtest_lib_only
# Disable C++ exception
conf.disable_cxx_exception
# All standard gems.
conf.gem 'mrbgems/mruby-array-ext/'
conf.gem 'mrbgems/mruby-bigint/'
conf.gem 'mrbgems/mruby-bin-config/'
conf.gem 'mrbgems/mruby-bin-debugger/'
conf.gem 'mrbgems/mruby-bin-mirb/'
conf.gem 'mrbgems/mruby-bin-mrbc/'
conf.gem 'mrbgems/mruby-bin-mruby/'
conf.gem 'mrbgems/mruby-bin-strip/'
conf.gem 'mrbgems/mruby-binding/'
conf.gem 'mrbgems/mruby-catch/'
conf.gem 'mrbgems/mruby-class-ext/'
# SDK doesn't include complex math for uClibc
# conf.gem 'mrbgems/mruby-cmath/'
conf.gem 'mrbgems/mruby-compar-ext/'
conf.gem 'mrbgems/mruby-compiler/'
conf.gem 'mrbgems/mruby-complex/'
conf.gem 'mrbgems/mruby-data/'
conf.gem 'mrbgems/mruby-dir/'
conf.gem 'mrbgems/mruby-enum-chain/'
conf.gem 'mrbgems/mruby-enum-ext/'
conf.gem 'mrbgems/mruby-enum-lazy/'
conf.gem 'mrbgems/mruby-enumerator/'
conf.gem 'mrbgems/mruby-errno/'
conf.gem 'mrbgems/mruby-error/'
conf.gem 'mrbgems/mruby-eval/'
conf.gem 'mrbgems/mruby-exit/'
conf.gem 'mrbgems/mruby-fiber/'
conf.gem 'mrbgems/mruby-hash-ext/'
conf.gem 'mrbgems/mruby-io/'
conf.gem 'mrbgems/mruby-kernel-ext/'
conf.gem 'mrbgems/mruby-math/'
conf.gem 'mrbgems/mruby-metaprog/'
conf.gem 'mrbgems/mruby-method/'
conf.gem 'mrbgems/mruby-numeric-ext/'
conf.gem 'mrbgems/mruby-object-ext/'
conf.gem 'mrbgems/mruby-objectspace/'
conf.gem 'mrbgems/mruby-os-memsize/'
conf.gem 'mrbgems/mruby-pack/'
conf.gem 'mrbgems/mruby-proc-binding/'
conf.gem 'mrbgems/mruby-proc-ext/'
conf.gem 'mrbgems/mruby-random/'
conf.gem 'mrbgems/mruby-range-ext/'
conf.gem 'mrbgems/mruby-rational/'
conf.gem 'mrbgems/mruby-set/'
conf.gem 'mrbgems/mruby-sleep/'
conf.gem 'mrbgems/mruby-socket/'
conf.gem 'mrbgems/mruby-sprintf/'
conf.gem 'mrbgems/mruby-string-ext/'
conf.gem 'mrbgems/mruby-struct/'
conf.gem 'mrbgems/mruby-symbol-ext/'
# conf.gem 'mrbgems/mruby-test-inline-struct/'
# conf.gem 'mrbgems/mruby-test/'
conf.gem 'mrbgems/mruby-time/'
conf.gem 'mrbgems/mruby-toplevel-ext/'
end

106
vendor/mruby/build_config/milkv_duo.rb vendored Normal file
View file

@ -0,0 +1,106 @@
# Cross Compiling configuration for Milk-V Duo.
# To build (on Ubuntu 24.04): rake MRUBY_CONFIG=build_config/milkv_duo.rb
#
# Requires: https://github.com/milkv-duo/duo-sdk
#
MRuby::CrossBuild.new("milkv_duo") do |conf|
# Set this string to match your board: milkv_duo, milkv_duo256m, milkv_duos
MILKV_DUO_VARIANT = "milkv_duo256m"
# Expect duo-sdk directory is same level as (next to) mruby top-level directory.
SDK_BASE = File.expand_path("../../../", File.expand_path(__FILE__)) + "/duo-sdk"
TOOLCHAIN_BASE = "#{SDK_BASE}/riscv64-linux-musl-x86_64"
SYSROOT = "#{SDK_BASE}/rootfs"
toolchain :gcc
# C compiler settings
conf.cc do |cc|
cc.command = "#{TOOLCHAIN_BASE}/bin/riscv64-unknown-linux-musl-gcc"
cc.include_paths << "#{TOOLCHAIN_BASE}/lib/gcc/riscv64-unknown-linux/musl/10.2.0/include-fixed"
cc.include_paths << "#{TOOLCHAIN_BASE}/lib/gcc/riscv64-unknown-linux/musl/10.2.0/include"
cc.include_paths << "#{TOOLCHAIN_BASE}/riscv64-unknown-linux/include"
cc.include_paths << "#{TOOLCHAIN_BASE}/include"
cc.include_paths << "#{SYSROOT}/usr/include"
cc.flags << ["-mcpu=c906fdv", "-march=rv64imafdcv0p7xthead", "-mcmodel=medany", "-mabi=lp64d"]
cc.flags << ["-D_LARGEFILE_SOURCE", "-D_LARGEFILE64_SOURCE", "-D_FILE_OFFSET_BITS=64"]
cc.flags << ["-Wl,--copy-dt-needed-entries", "-Wl,-lc,-lgcc_s,-lwiringx"]
cc.defines << "MILKV_DUO_VARIANT=_#{MILKV_DUO_VARIANT}"
end
# Linker settings
conf.linker do |linker|
linker.command = cc.command
linker.library_paths << ["#{SYSROOT}/lib", "#{SYSROOT}/usr/lib"]
linker.flags = cc.flags
end
# Archiver settings
conf.archiver do |archiver|
archiver.command = "#{TOOLCHAIN_BASE}/bin/riscv64-unknown-linux-musl-gcc-ar"
end
# Do not build executable test
conf.build_mrbtest_lib_only
# Disable C++ exception
conf.disable_cxx_exception
# All standard gems.
conf.gem 'mrbgems/mruby-array-ext/'
conf.gem 'mrbgems/mruby-bigint/'
conf.gem 'mrbgems/mruby-bin-config/'
conf.gem 'mrbgems/mruby-bin-debugger/'
conf.gem 'mrbgems/mruby-bin-mirb/'
conf.gem 'mrbgems/mruby-bin-mrbc/'
conf.gem 'mrbgems/mruby-bin-mruby/'
conf.gem 'mrbgems/mruby-bin-strip/'
conf.gem 'mrbgems/mruby-binding/'
conf.gem 'mrbgems/mruby-catch/'
conf.gem 'mrbgems/mruby-class-ext/'
conf.gem 'mrbgems/mruby-cmath/'
conf.gem 'mrbgems/mruby-compar-ext/'
conf.gem 'mrbgems/mruby-compiler/'
conf.gem 'mrbgems/mruby-complex/'
conf.gem 'mrbgems/mruby-data/'
conf.gem 'mrbgems/mruby-dir/'
conf.gem 'mrbgems/mruby-enum-chain/'
conf.gem 'mrbgems/mruby-enum-ext/'
conf.gem 'mrbgems/mruby-enum-lazy/'
conf.gem 'mrbgems/mruby-enumerator/'
conf.gem 'mrbgems/mruby-errno/'
conf.gem 'mrbgems/mruby-error/'
conf.gem 'mrbgems/mruby-eval/'
conf.gem 'mrbgems/mruby-exit/'
conf.gem 'mrbgems/mruby-fiber/'
conf.gem 'mrbgems/mruby-hash-ext/'
conf.gem 'mrbgems/mruby-io/'
conf.gem 'mrbgems/mruby-kernel-ext/'
conf.gem 'mrbgems/mruby-math/'
conf.gem 'mrbgems/mruby-metaprog/'
conf.gem 'mrbgems/mruby-method/'
conf.gem 'mrbgems/mruby-numeric-ext/'
conf.gem 'mrbgems/mruby-object-ext/'
conf.gem 'mrbgems/mruby-objectspace/'
conf.gem 'mrbgems/mruby-os-memsize/'
conf.gem 'mrbgems/mruby-pack/'
conf.gem 'mrbgems/mruby-proc-binding/'
conf.gem 'mrbgems/mruby-proc-ext/'
conf.gem 'mrbgems/mruby-random/'
conf.gem 'mrbgems/mruby-range-ext/'
conf.gem 'mrbgems/mruby-rational/'
conf.gem 'mrbgems/mruby-set/'
conf.gem 'mrbgems/mruby-sleep/'
conf.gem 'mrbgems/mruby-socket/'
conf.gem 'mrbgems/mruby-sprintf/'
conf.gem 'mrbgems/mruby-string-ext/'
conf.gem 'mrbgems/mruby-struct/'
conf.gem 'mrbgems/mruby-symbol-ext/'
# conf.gem 'mrbgems/mruby-test-inline-struct/'
# conf.gem 'mrbgems/mruby-test/'
conf.gem 'mrbgems/mruby-time/'
conf.gem 'mrbgems/mruby-toplevel-ext/'
# GPIO, ADC, PWM, I2C and SPI support for Milk-V Duo
# conf.gem :github => 'denko-rb/mruby-milkv-duo'
end

4
vendor/mruby/build_config/minimal.rb vendored Normal file
View file

@ -0,0 +1,4 @@
MRuby::CrossBuild.new('minimal') do |conf|
conf.toolchain :gcc
conf.cc.defines << 'MRB_NO_STDIO'
end

10
vendor/mruby/build_config/mrbc.rb vendored Normal file
View file

@ -0,0 +1,10 @@
MRuby::Build.new do |conf|
if ENV['VisualStudioVersion'] || ENV['VSINSTALLDIR']
conf.toolchain :visualcpp
else
conf.toolchain :gcc
end
conf.build_mrbc_exec
conf.disable_libmruby
end

View file

@ -0,0 +1,73 @@
# Cross Compiling configuration for the Nintendo Switch, it requires Nintendo SDK
# Tested on windows
MRuby::CrossBuild.new('nintendo_switch_32bit') do |conf|
conf.toolchain :clang
NINTENDO_SDK_PATH = ENV['NINTENDO_SDK_ROOT']
include_paths = [
"#{NINTENDO_SDK_PATH}/Include",
"#{NINTENDO_SDK_PATH}/Common/Configs/Targets/NX-NXFP2-a32/Include"
]
conf.cc do |cc|
cc.command = "#{NINTENDO_SDK_PATH}/Compilers/NX/bin/nx-clang++"
cc.include_paths += include_paths
cc.flags += ['-fpic -fno-short-enums -ffunction-sections -fdata-sections -fno-common -fno-strict-aliasing -fomit-frame-pointer -fno-vectorize -funsigned-char -O2 -g -mno-implicit-float']
cc.defines += 'NN_SDK_BUILD_RELEASE'
end
conf.cxx do |cxx|
cxx.command = "#{NINTENDO_SDK_PATH}/Compilers/NX/bin/nx-clang++"
cxx.include_paths += include_paths
cxx.flags += ['-fpic -fno-short-enums -ffunction-sections -fdata-sections -fno-common -fno-strict-aliasing -fomit-frame-pointer -fno-vectorize -funsigned-char -O2 -g -mno-implicit-float']
cxx.defines += 'NN_SDK_BUILD_RELEASE'
end
conf.archiver do |archiver|
archiver.command = "#{NINTENDO_SDK_PATH}/Compilers/NX/nx/armv7l/bin/llvm-ar"
end
conf.linker do |linker|
linker.command = "#{NINTENDO_SDK_PATH}/Compilers/NX/nx/armv7l/bin/clang++"
linker.libraries = []
end
# Add your mrbgems
end
MRuby::CrossBuild.new('nintendo_switch_64bit') do |conf|
conf.toolchain :clang
NINTENDO_SDK_PATH = ENV['NINTENDO_SDK_ROOT']
include_paths = [
"#{NINTENDO_SDK_PATH}/Include",
"#{NINTENDO_SDK_PATH}/Common/Configs/Targets/NX-NXFP2-a64/Include"
]
conf.cc do |cc|
cc.command = "#{NINTENDO_SDK_PATH}/Compilers/NX/bin/nx-clang++"
cc.include_paths += include_paths
cc.flags += ['-fpic -fno-short-enums -ffunction-sections -fdata-sections -fno-common -fno-strict-aliasing -fomit-frame-pointer -fno-vectorize -funsigned-char -O2 -g -mno-implicit-float']
cc.flags << '--target=aarch64-nintendo-nx-elf'
cc.defines += 'NN_SDK_BUILD_RELEASE'
end
conf.cxx do |cxx|
cxx.command = "#{NINTENDO_SDK_PATH}/Compilers/NX/bin/nx-clang++"
cxx.include_paths += include_paths
cxx.flags += ['-fpic -fno-short-enums -ffunction-sections -fdata-sections -fno-common -fno-strict-aliasing -fomit-frame-pointer -fno-vectorize -funsigned-char -O2 -g -mno-implicit-float']
cxx.flags << '--target=aarch64-nintendo-nx-elf'
cxx.defines += 'NN_SDK_BUILD_RELEASE'
end
conf.archiver do |archiver|
archiver.command = "#{NINTENDO_SDK_PATH}/Compilers/NX/nx/aarch64/bin/llvm-ar"
end
conf.linker do |linker|
linker.command = "#{NINTENDO_SDK_PATH}/Compilers/NX/nx/aarch64/bin/clang++"
linker.libraries = []
end
# Add your mrbgems
end

View file

@ -0,0 +1,95 @@
# Cross Compiling configuration for the Nintendo Wii
# This configuration requires devkitPPC
# https://devkitpro.org/wiki/Getting_Started
#
#
MRuby::CrossBuild.new("wii") do |conf|
toolchain :gcc
DEVKITPRO_PATH = "/opt/devkitpro"
BIN_PATH = "#{DEVKITPRO_PATH}/devkitPPC/bin"
# C compiler
conf.cc do |cc|
cc.command = "#{BIN_PATH}/powerpc-eabi-gcc"
cc.compile_options = %(%{flags} -o "%{outfile}" -c "%{infile}")
end
# C++ compiler
conf.cxx do |cxx|
cxx.command = "#{BIN_PATH}/powerpc-eabi-g++"
cxx.include_paths = conf.cc.include_paths.dup
cxx.flags = conf.cc.flags.dup
cxx.defines = conf.cc.defines.dup
cxx.compile_options = conf.cc.compile_options.dup
end
# Linker
conf.linker do |linker|
linker.command = "#{BIN_PATH}/powerpc-eabi-gcc"
end
# No executables
conf.bins = []
# Do not build executable test
conf.build_mrbtest_lib_only
# Disable C++ exception
conf.disable_cxx_exception
# All current core gems with ones with build issues commented out
conf.gem 'mrbgems/mruby-array-ext/'
conf.gem 'mrbgems/mruby-bigint/'
conf.gem 'mrbgems/mruby-bin-config/'
conf.gem 'mrbgems/mruby-bin-debugger/'
conf.gem 'mrbgems/mruby-bin-mirb/'
conf.gem 'mrbgems/mruby-bin-mrbc/'
conf.gem 'mrbgems/mruby-bin-mruby/'
conf.gem 'mrbgems/mruby-bin-strip/'
conf.gem 'mrbgems/mruby-binding/'
conf.gem 'mrbgems/mruby-catch/'
conf.gem 'mrbgems/mruby-class-ext/'
conf.gem 'mrbgems/mruby-cmath/'
conf.gem 'mrbgems/mruby-compar-ext/'
conf.gem 'mrbgems/mruby-compiler/'
conf.gem 'mrbgems/mruby-complex/'
conf.gem 'mrbgems/mruby-data/'
#conf.gem 'mrbgems/mruby-dir/'
conf.gem 'mrbgems/mruby-enum-chain/'
conf.gem 'mrbgems/mruby-enum-ext/'
conf.gem 'mrbgems/mruby-enum-lazy/'
conf.gem 'mrbgems/mruby-enumerator/'
conf.gem 'mrbgems/mruby-errno/'
conf.gem 'mrbgems/mruby-error/'
conf.gem 'mrbgems/mruby-eval/'
conf.gem 'mrbgems/mruby-exit/'
conf.gem 'mrbgems/mruby-fiber/'
conf.gem 'mrbgems/mruby-hash-ext/'
#conf.gem 'mrbgems/mruby-io/'
conf.gem 'mrbgems/mruby-kernel-ext/'
conf.gem 'mrbgems/mruby-math/'
conf.gem 'mrbgems/mruby-metaprog/'
conf.gem 'mrbgems/mruby-method/'
conf.gem 'mrbgems/mruby-numeric-ext/'
conf.gem 'mrbgems/mruby-object-ext/'
conf.gem 'mrbgems/mruby-objectspace/'
conf.gem 'mrbgems/mruby-os-memsize/'
conf.gem 'mrbgems/mruby-pack/'
conf.gem 'mrbgems/mruby-proc-binding/'
conf.gem 'mrbgems/mruby-proc-ext/'
conf.gem 'mrbgems/mruby-random/'
conf.gem 'mrbgems/mruby-range-ext/'
conf.gem 'mrbgems/mruby-rational/'
conf.gem 'mrbgems/mruby-set/'
conf.gem 'mrbgems/mruby-sleep/'
#conf.gem 'mrbgems/mruby-socket/'
conf.gem 'mrbgems/mruby-sprintf/'
conf.gem 'mrbgems/mruby-string-ext/'
conf.gem 'mrbgems/mruby-struct/'
conf.gem 'mrbgems/mruby-symbol-ext/'
conf.gem 'mrbgems/mruby-test-inline-struct/'
#conf.gem 'mrbgems/mruby-test/'
conf.gem 'mrbgems/mruby-time/'
conf.gem 'mrbgems/mruby-toplevel-ext/'
end

17
vendor/mruby/build_config/no-float.rb vendored Normal file
View file

@ -0,0 +1,17 @@
# Define cross build settings
MRuby::CrossBuild.new('no-float') do |conf|
conf.toolchain
# Add configuration
conf.compilers.each do |c|
c.defines << "MRB_NO_FLOAT"
end
conf.gem :core => "mruby-bin-mruby"
conf.test_runner.command = 'env'
conf.enable_debug
# conf.enable_bintest
conf.enable_test
end

View file

@ -0,0 +1,78 @@
# Cross Compiling configuration for the Sony PlayStation Portable.
# This configuration requires toolchain from https://github.com/pspdev
MRuby::CrossBuild.new("playstationportable") do |conf|
toolchain :gcc
PSPDEV_PATH = "#{ENV['PSPDEV']}"
BIN_PATH = "#{PSPDEV_PATH}/bin"
# C compiler
conf.cc do |cc|
cc.command = "#{BIN_PATH}/psp-gcc"
cc.flags << ["-O2", "-D_PSP_FW_VERSION=600"]
cc.include_paths << ["#{PSPDEV_PATH}/psp/include", "#{PSPDEV_PATH}/psp/sdk/include"]
cc.compile_options = %(%{flags} -o "%{outfile}" -c "%{infile}")
end
# C++ compiler
conf.cxx do |cxx|
cxx.command = "#{BIN_PATH}/psp-g++"
cxx.include_paths = conf.cc.include_paths.dup
cxx.flags = conf.cc.flags.dup
cxx.flags << %w[-fno-rtti -fno-exceptions]
cxx.defines = conf.cc.defines.dup
cxx.compile_options = conf.cc.compile_options.dup
end
# Linker
conf.linker do |linker|
linker.command = "#{BIN_PATH}/psp-gcc"
linker.flags << ["-Wl,-zmax-page-size=128"]
end
# No executables
conf.bins = []
# Do not build executable test
conf.build_mrbtest_lib_only
# Gems from core
conf.gem :core => "mruby-metaprog"
conf.gem :core => "mruby-pack"
conf.gem :core => "mruby-sprintf"
conf.gem :core => "mruby-math"
conf.gem :core => "mruby-time"
conf.gem :core => "mruby-struct"
conf.gem :core => "mruby-compar-ext"
conf.gem :core => "mruby-enum-ext"
conf.gem :core => "mruby-string-ext"
conf.gem :core => "mruby-numeric-ext"
conf.gem :core => "mruby-array-ext"
conf.gem :core => "mruby-hash-ext"
conf.gem :core => "mruby-range-ext"
conf.gem :core => "mruby-proc-ext"
conf.gem :core => "mruby-symbol-ext"
conf.gem :core => "mruby-random"
conf.gem :core => "mruby-object-ext"
conf.gem :core => "mruby-objectspace"
conf.gem :core => "mruby-fiber"
conf.gem :core => "mruby-enumerator"
conf.gem :core => "mruby-enum-lazy"
conf.gem :core => "mruby-toplevel-ext"
conf.gem :core => "mruby-kernel-ext"
conf.gem :core => "mruby-class-ext"
conf.gem :core => "mruby-compiler"
conf.gem :core => "mruby-binding"
conf.gem :core => "mruby-catch"
conf.gem :core => "mruby-enum-chain"
conf.gem :core => "mruby-errno"
conf.gem :core => "mruby-error"
conf.gem :core => "mruby-exit"
conf.gem :core => "mruby-os-memsize"
conf.gem :core => "mruby-proc-binding"
conf.gem :core => "mruby-sleep"
conf.gem :core => "mruby-io"
conf.gem :core => "mruby-dir"
#conf.gem :core => "mruby-socket" unsupported
end

26
vendor/mruby/build_config/serenity.rb vendored Normal file
View file

@ -0,0 +1,26 @@
# Cross compiling configuration for SerenityOS
# Graphical Unix-like operating system for x86 computers.
# https://github.com/SerenityOS/serenity
#
# Should be built using the SerenityOS Ports system
# https://github.com/SerenityOS/serenity/tree/master/Ports
#
# As of 2021/08/20, SERENITY_ARCH is defined in the SerenityOS Ports
# build script to always be either "i686" or "x86_64"
MRuby::CrossBuild.new('serenity') do |conf|
conf.toolchain :gcc
conf.archiver.command = "#{ENV['SERENITY_ARCH']}-pc-serenity-ar"
conf.linker.command = "#{ENV['SERENITY_ARCH']}-pc-serenity-g++"
conf.cxx.command = "#{ENV['SERENITY_ARCH']}-pc-serenity-g++"
conf.cxx.defines << (ENV['SERENITY_ARCH'].include?('64') ? 'MRB_64BIT' : 'MRB_32BIT')
conf.cc.command = "#{ENV['SERENITY_ARCH']}-pc-serenity-gcc"
conf.cc.defines << (ENV['SERENITY_ARCH'].include?('64') ? 'MRB_64BIT' : 'MRB_32BIT')
conf.gembox 'full-core'
conf.test_runner.command = 'env'
end

13
vendor/mruby/docker-compose.yml vendored Normal file
View file

@ -0,0 +1,13 @@
version: "3.8"
services:
test:
build:
context: .
command: sh -c 'rake deep_clean && rake -m test:run:serial'
environment:
- MRUBY_CONFIG=ci/gcc-clang
- CC=gcc
- CXX=g++
- LD=gcc
- SKIP=check-executables-have-shebangs
working_dir: /app

View file

@ -0,0 +1,3 @@
# C and Ruby Extension Example
This is an example gem which implements a C and Ruby extension.

View file

@ -0,0 +1,23 @@
MRuby::Gem::Specification.new('c_and_ruby_extension_example') do |spec|
spec.license = 'MIT'
spec.author = 'mruby developers'
# Add compile flags
# spec.cc.flags << ''
# Add cflags to all
# spec.mruby.cc.flags << '-g'
# Add libraries
# spec.linker.libraries << 'external_lib'
# Default build files
# spec.rbfiles = Dir.glob("#{dir}/mrblib/*.rb")
# spec.objs = Dir.glob("#{dir}/src/*.{c,cpp,m,asm,S}").map { |f| objfile(f.relative_path_from(dir).pathmap("#{build_dir}/%X")) }
# spec.test_rbfiles = Dir.glob("#{dir}/test/*.rb")
# spec.test_objs = Dir.glob("#{dir}/test/*.{c,cpp,m,asm,S}").map { |f| objfile(f.relative_path_from(dir).pathmap("#{build_dir}/%X")) }
# spec.test_preload = 'test/assert.rb'
# Values accessible as TEST_ARGS inside test scripts
# spec.test_args = {'tmp_dir' => Dir::tmpdir}
end

View file

@ -0,0 +1,5 @@
module CRubyExtension
def CRubyExtension.ruby_method
puts "#{self}: A Ruby Extension"
end
end

View file

@ -0,0 +1,23 @@
#include <mruby.h>
#include <mruby/string.h>
#include <stdio.h>
static mrb_value
mrb_c_method(mrb_state *mrb, mrb_value self)
{
mrb_ensure_string_type(mrb, self);
printf("%s: A C Extension\n", mrb_str_to_cstr(mrb, self));
return self;
}
void
mrb_c_and_ruby_extension_example_gem_init(mrb_state* mrb) {
struct RClass *class_cextension = mrb_define_module(mrb, "CRubyExtension");
mrb_define_class_method(mrb, class_cextension, "c_method", mrb_c_method, MRB_ARGS_NONE());
}
void
mrb_c_and_ruby_extension_example_gem_final(mrb_state* mrb) {
/* finalizer */
}

View file

@ -0,0 +1,7 @@
assert('C and Ruby Extension Example 1') do
CRubyExtension.respond_to? :c_method
end
assert('C and Ruby Extension Example 2') do
CRubyExtension.respond_to? :ruby_method
end

View file

@ -0,0 +1,3 @@
# C Extension Example
This is an example gem which implements a C extension.

View file

@ -0,0 +1,23 @@
MRuby::Gem::Specification.new('c_extension_example') do |spec|
spec.license = 'MIT'
spec.author = 'mruby developers'
# Add compile flags
# spec.cc.flags << '-g'
# Add cflags to all
# spec.mruby.cc.flags << '-g'
# Add libraries
# spec.linker.libraries << 'external_lib'
# Default build files
# spec.rbfiles = Dir.glob("#{dir}/mrblib/*.rb")
# spec.objs = Dir.glob("#{dir}/src/*.{c,cpp,m,asm,S}").map { |f| objfile(f.relative_path_from(dir).pathmap("#{build_dir}/%X")) }
# spec.test_rbfiles = Dir.glob("#{dir}/test/*.rb")
# spec.test_objs = Dir.glob("#{dir}/test/*.{c,cpp,m,asm,S}").map { |f| objfile(f.relative_path_from(dir).pathmap("#{build_dir}/%X")) }
# spec.test_preload = 'test/assert.rb'
# Values accessible as TEST_ARGS inside test scripts
# spec.test_args = {'tmp_dir' => Dir::tmpdir}
end

View file

@ -0,0 +1,23 @@
#include <mruby.h>
#include <mruby/string.h>
#include <stdio.h>
static mrb_value
mrb_c_method(mrb_state *mrb, mrb_value self)
{
mrb_ensure_string_type(mrb, self);
printf("%s: A C Extension\n", mrb_str_to_cstr(mrb, self));
return self;
}
void
mrb_c_extension_example_gem_init(mrb_state* mrb) {
struct RClass *class_cextension = mrb_define_module(mrb, "CExtension");
mrb_define_class_method(mrb, class_cextension, "c_method", mrb_c_method, MRB_ARGS_NONE());
}
void
mrb_c_extension_example_gem_final(mrb_state* mrb) {
/* finalizer */
}

View file

@ -0,0 +1,7 @@
#include <mruby.h>
void
mrb_c_extension_example_gem_test(mrb_state *mrb)
{
/* test initializer in C */
}

View file

@ -0,0 +1,3 @@
assert('C Extension Example') do
CExtension.respond_to? :c_method
end

View file

@ -0,0 +1,3 @@
# C Data Extension Example
This is an example gem which implements a C extension with Data.

View file

@ -0,0 +1,23 @@
MRuby::Gem::Specification.new('cdata_extension_example') do |spec|
spec.license = 'MIT'
spec.author = 'mruby developers'
# Add compile flags
# spec.cc.flags << '-g'
# Add cflags to all
# spec.mruby.cc.flags << '-g'
# Add libraries
# spec.linker.libraries << 'external_lib'
# Default build files
# spec.rbfiles = Dir.glob("#{dir}/mrblib/*.rb")
# spec.objs = Dir.glob("#{dir}/src/*.{c,cpp,m,asm,S}").map { |f| objfile(f.relative_path_from(dir).pathmap("#{build_dir}/%X")) }
# spec.test_rbfiles = Dir.glob("#{dir}/test/*.rb")
# spec.test_objs = Dir.glob("#{dir}/test/*.{c,cpp,m,asm,S}").map { |f| objfile(f.relative_path_from(dir).pathmap("#{build_dir}/%X")) }
# spec.test_preload = 'test/assert.rb'
# Values accessible as TEST_ARGS inside test scripts
# spec.test_args = {'tmp_dir' => Dir::tmpdir}
end

Some files were not shown because too many files have changed in this diff Show more