From f26f497131923886889deb4b843b179518888b1f Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sat, 13 Jul 2024 14:10:40 +0900 Subject: feat: add examples/hello-world --- README.md | 8 ++++ composer.json | 1 + examples/hello-world/index.php | 35 ++++++++++++++++ phpstan.neon | 1 + src/Stream/BlobStream.php | 95 ++++++++++++++++++++++++++++++++++++++++++ src/Stream/StreamInterface.php | 8 ++-- 6 files changed, 144 insertions(+), 4 deletions(-) create mode 100644 examples/hello-world/index.php create mode 100644 src/Stream/BlobStream.php 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 @@ +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 @@ + + */ + 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 */ -- cgit v1.2.3-70-g09d2