Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/m3m0r7/rubyvm-on-php
A RubyVM written in PHP
https://github.com/m3m0r7/rubyvm-on-php
Last synced: 5 days ago
JSON representation
A RubyVM written in PHP
- Host: GitHub
- URL: https://github.com/m3m0r7/rubyvm-on-php
- Owner: m3m0r7
- License: mit
- Created: 2023-07-12T12:46:59.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2024-01-02T13:53:30.000Z (about 1 year ago)
- Last Synced: 2024-11-13T15:08:02.810Z (2 months ago)
- Language: PHP
- Homepage: https://i.mem.ooo
- Size: 5.35 MB
- Stars: 23
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# RubyVM on PHP
The RubyVM on PHP is implementation RubyVM written in PHP 100%.
Completely documentation not exists how to implement RubyVM, and I was referred [Ruby source code](https://github.com/ruby/ruby) when contributing this project._Notice: This project is very ultra super hyper maximum experimental implementation_
_Notice: I tested Ruby version 3.2 and 3.3 only_
### See also
- https://github.com/ruby/ruby/blob/master/compile.c
- https://github.com/ruby/ruby/blob/master/vm.c
- https://github.com/ruby/ruby/blob/master/vm_exec.c## DEMO
## Requirement
- PHP 8.2+
## Currently status
- Implemented general syntax (define local variables, global variables, classes, methods, booleans, hashes, arrays and so on)
- Implemented arithmetics (`+`, `-`, `*`, `/`), bit calculating (`|`, `&`, `<<`, `>>`), some operator (`**`, `%`) and available overwrite it
- Implemented the block syntax (`[].each do | var | ... end`) and non block syntax (`[].push`)
- Implemented keyword arguments when calling a method (`keyword_argument(a: "Hello", c: "!", b: "World")`)
- Implemented variadic arguments when using an array and calling a method (`[*var1, *var2]`, `keyword_argument(a, b, *c)`)
- Implemented partially ruby methods (`to_s`, `to_i`, `[].push`, `foobar.nil?`)
- Implemented case-when syntax
- Implemented regexp syntax (`p /Hello/ =~ "Hello World"`)
- Implemented raise/rescue
- and anymore (see the tests' directory)## Quick start
1. Install via composer as following
```
$ composer require m3m0r7/rubyvm-on-php
```2. Save the below code as `HelloWorld.rb`
```ruby
puts RubyVM::InstructionSequence.compile("puts 'HelloWorld!\n'", "HelloWorld.rb").to_binary
```3. Output `.yarv` file as following
```shell
$ ruby HelloWorld.rb > HelloWorld.yarv
```3. Create PHP file with below code and save as `HelloWorld.php`
```php
disassemble();// You can choose to run ruby version if you needed
// $executor = $rubyVM->disassemble(
// useVersion: \RubyVM\RubyVersion::VERSION_3_2,
// );// Execute disassembled instruction sequence
$executor->execute();
```4. Run `php HelloWorld.php` and you will get outputted `HelloWorld!` from RubyVM.
## Call defined ruby method on PHP
1. Create ruby code as below:
```ruby
def callFromPHP
puts "Hello World from Ruby!"
end
```And then, save file as `test.rb`
2. Compile to YARV as below:
```
$ ruby -e "puts RubyVM::InstructionSequence.compile_file('test.rb').to_binary" > test.yarv
```3. Call ruby method on PHP as below:
```php
disassemble();// Execute disassembled instruction sequence
$executed = $executor->execute();// Call Ruby method as below code.
// In this case, you did define method name is `callFromPHP`.
$executed->context()->callFromPHP();
```You will get to output `Hello World from Ruby!`.
In addition case, maybe you want to pass arguments. of course, it is available on.
First time, to modify previous code as below.```ruby
def callFromPHP(text)
puts text
end
```Second time, to modify PHP code `$executed->context()->callFromPHP()` as following:
```php
$executed->context()->callFromPHP('Hello World! Here is passed an argument from PHP!')
```You will get to output `Hello World! Here is passed an argument from PHP`.
## Use an executor debugger
The RubyVM on PHP is provided an executor debugger that can display processed an INSN and anymore into a table as following:
```
+-----+--------------------------------+-------------------------------+--------------------------------+--------------+
| PC | CALLEE | INSN | CURRENT STACKS | LOCAL TABLES |
+-----+--------------------------------+-------------------------------+--------------------------------+--------------+
| 0 | | [0x12] putself | | |
+-----+--------------------------------+-------------------------------+--------------------------------+--------------+
| 1 | | [0x15] putstring | Main#0 | |
+-----+--------------------------------+-------------------------------+--------------------------------+--------------+
| 3 | | [0x33] opt_send_without_block | Main#0, String(Hello World!)#1 | |
| | | (Main#puts(Hello World!)) | | |
+-----+--------------------------------+-------------------------------+--------------------------------+--------------+
| 5 | | [0x3c] leave | Nil(nil)#0 | |
+-----+--------------------------------+-------------------------------+--------------------------------+--------------+
```If you want to display above table then add below code from the Quick start.
_Notice: The executor debugger is using a lot of memories. We recommend to use disabling ordinarily. In depending on the case, may be using `-d memory_limit=NEEDING_MEMORY_BYTES` parameters to be working when calling `php` command_
```php
// You can display processed an INSN table when adding below code
$executor->context()->option()->debugger()->showExecutedOperations();
```### Step by step debugging
The RubyVM on PHP is providing step by step debugger. It is available to confirm to process a sequence step by step.
Which collect previous stacks, registered local tables and so on. this is required debugging this project.```php
// Use breakpoint debugger with option$rubyVM = new \RubyVM\VM\Core\Runtime\RubyVM(
new \RubyVM\VM\Core\Runtime\Option(
// excluded...debugger: new \RubyVM\VM\Core\Runtime\Executor\Debugger\StepByStepDebugger(),
),
);
```When you enabled it, displays as below:
```
+-----+--------------------------------+-------------------------------+--------------------------------+--------------+
| PC | CALLEE | INSN | CURRENT STACKS | LOCAL TABLES |
+-----+--------------------------------+-------------------------------+--------------------------------+--------------+
| 0 | | [0x12] putself | | |
+-----+--------------------------------+-------------------------------+--------------------------------+--------------+
| 1 | | [0x15] putstring | Main#0 | |
+-----+--------------------------------+-------------------------------+--------------------------------+--------------+
Current INSN: putstring(0x15)
Previous Stacks: [total: 1, OperandEntry]#966
Previous Local Tables: []
Current Stacks: [total: 2, OperandEntry, OperandEntry]#561
Current Local Tables: []Enter to next step (y/n/q):
```## Custom method
The RubyVM on PHP has custom method in the main context.
Try to call `phpinfo` as below Ruby code on the RubyVM on PHP:```ruby
phpinfo
```Then you got displayed `PHP Version: 8.2.7`
## Test
```
$ ./vendor/bin/phpunit tests/
```## Linter
```
./vendor/bin/php-cs-fixer fix --allow-risky=yes
```## How to contribute
1) Build your ruby environment from source code with `-DIBF_ISEQ_DEBUG` flag
See: https://docs.ruby-lang.org/en/master/contributing/building_ruby_md.html
```
$ git clone [email protected]:ruby/ruby.git
$ mkdir build && cd build
$ ../configure cppflags="-DIBF_ISEQ_DEBUG=1"
$ make -j$(nproc)
```2) When you built ruby environment, you will got `vm.inc` file which is wrote how to execute each INSN commands
3) You can get logging at `ibf_load_**` when running ruby code as following
```
...omittedibf_load_object: type=0x15 special=1 frozen=1 internal=1 // The type is a FIX_NUMBER (2)
ibf_load_object: index=0x3 obj=0x5
ibf_load_object: list=0xf0 offsets=0x12b80fcf0 offset=0xe1
ibf_load_object: type=0x15 special=1 frozen=1 internal=1 // The type is a FIX_NUMBER (3)
ibf_load_object: index=0x4 obj=0x7
ibf_load_object: list=0xf0 offsets=0x12b80fcf0 offset=0xcd
ibf_load_object: type=0x5 special=0 frozen=1 internal=0 // The type is a STRING SYMBOL (puts)...omitted
```The above logs is created below example code:
```ruby
puts 1 + 2 + 3
```4) Refer it and now you can contribute to implement INSN command in the RubyVM on PHP
## Other my toys
- [PHPJava](https://github.com/php-java/php-java) - Implement a JVM written in PHP
- [nfc-for-php](https://github.com/m3m0r7/nfc-for-php) - A NFC Reader (Control a NFC hardware) written in PHP
- [PHPPython](https://github.com/m3m0r7/PHPPython) - Implement a PYC executor written in PHP