aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2024-07-13 14:10:40 +0900
committernsfisis <nsfisis@gmail.com>2024-07-13 14:10:40 +0900
commitf26f497131923886889deb4b843b179518888b1f (patch)
tree10ff8467135865d4aadb6bf4d3978dd1d011ed1a
parent1f4170811730477e9cd7d9620608c4ab619bdefc (diff)
downloadphp-waddiwasi-f26f497131923886889deb4b843b179518888b1f.tar.gz
php-waddiwasi-f26f497131923886889deb4b843b179518888b1f.tar.zst
php-waddiwasi-f26f497131923886889deb4b843b179518888b1f.zip
feat: add examples/hello-world
-rw-r--r--README.md8
-rw-r--r--composer.json1
-rw-r--r--examples/hello-world/index.php35
-rw-r--r--phpstan.neon1
-rw-r--r--src/Stream/BlobStream.php95
-rw-r--r--src/Stream/StreamInterface.php8
6 files changed, 144 insertions, 4 deletions
diff --git a/README.md b/README.md
index 4c8c9d6..6782e97 100644
--- a/README.md
+++ b/README.md
@@ -8,6 +8,13 @@ It is partially compatible with the WebAssembly specification version 2.0.
## Examples
+### Hello, World!
+
+```
+$ composer example:hello-world
+```
+
+
### PHP on Wasm
The PHP runtime can be compiled to WebAssembly binary. This Wasm runtime can execute it. Currently, "Hello, World!" program works on the PHP runtime on the Wasm runtime.
@@ -16,6 +23,7 @@ The PHP runtime can be compiled to WebAssembly binary. This Wasm runtime can exe
$ composer example:php-on-wasm
```
+
### RubyVM on PHP on Wasm
https://github.com/m3m0r7/rubyvm-on-php is a RubyVM written in pure PHP.
diff --git a/composer.json b/composer.json
index 4324026..d459092 100644
--- a/composer.json
+++ b/composer.json
@@ -33,6 +33,7 @@
],
"ecs": "ecs check",
"ecsfix": "ecs --memory-limit=1G check --fix",
+ "example:hello-world": "@php examples/hello-world/index.php",
"example:php-on-wasm": "@php -d memory_limit=256M -d opcache.enable_cli=on -d opcache.jit=on -d opcache.jit_buffer_size=1G examples/php-on-wasm/php-wasm.php",
"example:rubyvm-on-php-on-wasm": "@php -d memory_limit=-1 -d opcache.enable_cli=on -d opcache.jit=on -d opcache.jit_buffer_size=2G examples/rubyvm-on-php-on-wasm/php-wasm.php",
"lint": [
diff --git a/examples/hello-world/index.php b/examples/hello-world/index.php
new file mode 100644
index 0000000..9b0b1bd
--- /dev/null
+++ b/examples/hello-world/index.php
@@ -0,0 +1,35 @@
+<?php
+
+declare(strict_types=1);
+
+require_once __DIR__ . '/../../vendor/autoload.php';
+
+use Nsfisis\Waddiwasi\Stream\BlobStream;
+use Nsfisis\Waddiwasi\WebAssembly\BinaryFormat\Decoder;
+use Nsfisis\Waddiwasi\WebAssembly\Execution\Extern;
+use Nsfisis\Waddiwasi\WebAssembly\Execution\FuncInst;
+use Nsfisis\Waddiwasi\WebAssembly\Execution\Linker;
+use Nsfisis\Waddiwasi\WebAssembly\Execution\Runtime;
+use Nsfisis\Waddiwasi\WebAssembly\Execution\Store;
+use Nsfisis\Waddiwasi\WebAssembly\Structure\Types\FuncType;
+use Nsfisis\Waddiwasi\WebAssembly\Structure\Types\ValType;
+
+$wasmBinary = (""
+ . "\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x08\x02\x60\x00\x00\x60\x01"
+ . "\x7f\x00\x02\x09\x01\x00\x04\x70\x75\x74\x63\x00\x01\x03\x02\x01"
+ . "\x00\x07\x08\x01\x04\x6d\x61\x69\x6e\x00\x01\x0a\x46\x01\x44\x00"
+ . "\x41\xc8\x00\x10\x00\x41\xe5\x00\x10\x00\x41\xec\x00\x10\x00\x41"
+ . "\xec\x00\x10\x00\x41\xef\x00\x10\x00\x41\x2c\x10\x00\x41\x20\x10"
+ . "\x00\x41\xd7\x00\x10\x00\x41\xef\x00\x10\x00\x41\xf2\x00\x10\x00"
+ . "\x41\xec\x00\x10\x00\x41\xe4\x00\x10\x00\x41\x21\x10\x00\x41\x0a"
+ . "\x10\x00\x0b");
+$module = (new Decoder(new BlobStream($wasmBinary)))->decode();
+
+$store = Store::empty();
+$linker = new Linker($store);
+
+$linker->register('', 'putc', Extern::Func(FuncInst::Host(new FuncType([ValType::I32], []), function (Runtime $runtime, int $c) { printf('%c', $c); })));
+
+$runtime = Runtime::instantiate($store, $module, $linker->resolve($module));
+
+$runtime->invoke('main', []);
diff --git a/phpstan.neon b/phpstan.neon
index a3d6227..fd3341e 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -8,6 +8,7 @@ parameters:
tipsOfTheDay: false
paths:
- src
+ - examples/hello-world
- examples/php-on-wasm
typeAliases:
Byte: 'int'
diff --git a/src/Stream/BlobStream.php b/src/Stream/BlobStream.php
new file mode 100644
index 0000000..972b8f6
--- /dev/null
+++ b/src/Stream/BlobStream.php
@@ -0,0 +1,95 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Nsfisis\Waddiwasi\Stream;
+
+use function assert;
+use function ord;
+use function strlen;
+use function substr;
+
+/**
+ * Read-only blob stream.
+ */
+final class BlobStream implements StreamInterface
+{
+ /**
+ * @var int<0, max>
+ */
+ private int $pos = 0;
+
+ /**
+ * @var positive-int
+ */
+ private readonly int $len;
+
+ /**
+ * Creates a new blob stream with the given content.
+ *
+ * @param non-empty-string $content
+ * The content of the blob.
+ */
+ public function __construct(
+ private readonly string $content,
+ ) {
+ $this->len = strlen($content);
+ }
+
+ public function close(): void
+ {
+ }
+
+ public function read(int $bytes): string
+ {
+ $this->ensureNBytesAvailable($bytes);
+ $ret = substr($this->content, $this->pos, $bytes);
+ $this->pos += $bytes;
+ assert($ret !== '');
+ return $ret;
+ }
+
+ public function readByte(): int
+ {
+ $this->ensureNBytesAvailable(1);
+ return ord($this->content[$this->pos++]);
+ }
+
+ public function peekByte(): int
+ {
+ $this->ensureNBytesAvailable(1);
+ return ord($this->content[$this->pos]);
+ }
+
+ public function seek(int $bytes): void
+ {
+ $this->ensureNBytesAvailable($bytes);
+ $this->pos += $bytes;
+ }
+
+ /**
+ * @phpstan-pure
+ */
+ public function tell(): int
+ {
+ return $this->pos;
+ }
+
+ /**
+ * @phpstan-pure
+ */
+ public function eof(): bool
+ {
+ return $this->len <= $this->pos;
+ }
+
+ /**
+ * @param positive-int $bytes
+ */
+ private function ensureNBytesAvailable(int $bytes): void
+ {
+ if ($this->len < $this->pos + $bytes) {
+ throw new UnexpectedEofException(sprintf("Unexpected EOF while reading from blob (%d bytes expected, %d bytes read)", $bytes, $this->len - $this->pos));
+ }
+ }
+}
diff --git a/src/Stream/StreamInterface.php b/src/Stream/StreamInterface.php
index 0655d22..723c38b 100644
--- a/src/Stream/StreamInterface.php
+++ b/src/Stream/StreamInterface.php
@@ -15,7 +15,7 @@ interface StreamInterface
* A binary string of $bytes bytes.
*
* @throws UnexpectedEofException
- * Thrown if the stream does not have enough bytes to read.
+ * If the stream does not have enough bytes to read.
*
* @phpstan-impure
*/
@@ -28,7 +28,7 @@ interface StreamInterface
* An 8-bit unsigned integer read from the stream.
*
* @throws UnexpectedEofException
- * Thrown if the stream have reached the end.
+ * If the stream have reached the end.
*
* @phpstan-impure
*/
@@ -41,7 +41,7 @@ interface StreamInterface
* An 8-bit unsigned integer read from the stream.
*
* @throws UnexpectedEofException
- * Thrown if the stream have reached the end.
+ * If the stream have reached the end.
*
* @phpstan-impure
*/
@@ -53,7 +53,7 @@ interface StreamInterface
* @param positive-int $bytes
*
* @throws UnexpectedEofException
- * Thrown if the stream does not have enough bytes to seek.
+ * If the stream does not have enough bytes to seek.
*
* @phpstan-impure
*/