Skip to content

Commit

Permalink
Merge pull request #21 from m3m0r7/fix-callinfo
Browse files Browse the repository at this point in the history
Fix callinfo cannot call on instantiated class
  • Loading branch information
m3m0r7 authored Sep 27, 2023
2 parents 7514173 + a5b6c1b commit 350c865
Show file tree
Hide file tree
Showing 16 changed files with 182 additions and 41 deletions.
5 changes: 3 additions & 2 deletions src/VM/Core/Runtime/Entity/Array_.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use RubyVM\VM\Core\Runtime\Executor\Context\ContextInterface;
use RubyVM\VM\Core\Runtime\Executor\Executor;
use RubyVM\VM\Core\Runtime\Option;
use RubyVM\VM\Core\YARV\Criterion\InstructionSequence\CallInfoInterface;
use RubyVM\VM\Core\YARV\Essential\Symbol\ArraySymbol;
use RubyVM\VM\Core\YARV\Essential\Symbol\SymbolInterface;
use RubyVM\VM\Exception\RuntimeException;
Expand All @@ -34,7 +35,7 @@ public function new(RubyClassInterface|array $values = null): self
return $this;
}

public function each(ContextInterface $context): RubyClassInterface
public function each(CallInfoInterface $callInfo, ContextInterface $context): RubyClassInterface
{
/**
* @var ArraySymbol $symbol
Expand Down Expand Up @@ -90,7 +91,7 @@ public function each(ContextInterface $context): RubyClassInterface
->toBeRubyClass();
}

public function push(RubyClassInterface $object): self
public function push(CallInfoInterface $callInfo, RubyClassInterface $object): self
{
// @phpstan-ignore-next-line
$this->symbol[] = $object->entity()->symbol();
Expand Down
19 changes: 10 additions & 9 deletions src/VM/Core/Runtime/Entity/Number.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

namespace RubyVM\VM\Core\Runtime\Entity;

use RubyVM\VM\Core\Runtime\RubyClass;
use RubyVM\VM\Core\Runtime\Essential\RubyClassInterface;
use RubyVM\VM\Core\YARV\Criterion\InstructionSequence\CallInfoInterface;
use RubyVM\VM\Core\YARV\Essential\Symbol\NumberSymbol;

class Number extends Entity implements EntityInterface
Expand All @@ -19,31 +20,31 @@ public function testValue(): bool
return (bool) $this->symbol->valueOf();
}

public function xor(RubyClass $object): Number
public function xor(CallInfoInterface $callInfo, RubyClassInterface $object): Number
{
return Number::createBy(
$this->symbol->valueOf() ^ $object->entity->symbol()->valueOf(),
$this->symbol->valueOf() ^ $object->entity()->symbol()->valueOf(),
);
}

public function power(RubyClass $object): Number
public function power(CallInfoInterface $callInfo, RubyClassInterface $object): Number
{
return Number::createBy(
$this->symbol->valueOf() ** $object->entity->symbol()->valueOf(),
$this->symbol->valueOf() ** $object->entity()->symbol()->valueOf(),
);
}

public function rightShift(RubyClass $object): Number
public function rightShift(CallInfoInterface $callInfo, RubyClassInterface $object): Number
{
return Number::createBy(
$this->symbol->valueOf() >> $object->entity->symbol()->valueOf(),
$this->symbol->valueOf() >> $object->entity()->symbol()->valueOf(),
);
}

public function compareStrictEquals(RubyClass $object): Boolean_
public function compareStrictEquals(CallInfoInterface $callInfo, RubyClassInterface $object): Boolean_
{
return Boolean_::createBy(
$this->symbol->valueOf() === $object->entity->symbol()->valueOf(),
$this->symbol->valueOf() === $object->entity()->symbol()->valueOf(),
);
}

Expand Down
3 changes: 2 additions & 1 deletion src/VM/Core/Runtime/Entity/Range.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use RubyVM\VM\Core\Runtime\Executor\Executor;
use RubyVM\VM\Core\Runtime\Executor\LocalTableHelper;
use RubyVM\VM\Core\Runtime\Option;
use RubyVM\VM\Core\YARV\Criterion\InstructionSequence\CallInfoInterface;
use RubyVM\VM\Core\YARV\Essential\Symbol\RangeSymbol;

class Range extends Entity implements EntityInterface
Expand All @@ -18,7 +19,7 @@ public function __construct(RangeSymbol $symbol)
$this->symbol = $symbol;
}

public function each(ContextInterface $context): EntityInterface
public function each(CallInfoInterface $callInfo, ContextInterface $context): EntityInterface
{
foreach ($this->symbol->valueOf() as $index => $number) {
$executor = (new Executor(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@

namespace RubyVM\VM\Core\Runtime\Essential;

use RubyVM\VM\Core\YARV\Criterion\InstructionSequence\CallInfoInterface;

interface RubyClassImplementationInterface
{
public function puts(RubyClassInterface $object): RubyClassInterface;
public function puts(CallInfoInterface $callInfo, RubyClassInterface $object): RubyClassInterface;

public function exit(int $code = 0): void;
public function exit(CallInfoInterface $callInfo, int $code = 0): never;
}
40 changes: 40 additions & 0 deletions src/VM/Core/Runtime/Executor/Accessor/BridgeCallData.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

declare(strict_types=1);

namespace RubyVM\VM\Core\Runtime\Executor\Accessor;

use RubyVM\VM\Core\Runtime\Essential\RubyClassInterface;
use RubyVM\VM\Core\YARV\Criterion\InstructionSequence\CallDataInterface;
use RubyVM\VM\Core\YARV\Essential\ID;
use RubyVM\VM\Core\YARV\Essential\Symbol\StringSymbol;

class BridgeCallData implements CallDataInterface
{
/**
* @param RubyClassInterface[] $arguments
*/
public function __construct(private readonly string $name, private readonly array $arguments) {}

public function flag(): int
{
// Always public
return 0;
}

public function mid(): ID
{
return new ID(new StringSymbol($this->name));
}

public function argumentsCount(): int
{
return count($this->arguments);
}

public function keywords(): ?array
{
// TODO: we must implement accepting keywords arguments on PHP
return null;
}
}
25 changes: 25 additions & 0 deletions src/VM/Core/Runtime/Executor/Accessor/BridgeCallInfo.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

namespace RubyVM\VM\Core\Runtime\Executor\Accessor;

use RubyVM\VM\Core\Runtime\Essential\RubyClassInterface;
use RubyVM\VM\Core\YARV\Criterion\InstructionSequence\CallDataInterface;
use RubyVM\VM\Core\YARV\Criterion\InstructionSequence\CallInfoInterface;

class BridgeCallInfo implements CallInfoInterface
{
/**
* @param RubyClassInterface[] $arguments
*/
public function __construct(private readonly string $name, private readonly array $arguments) {}

public function callData(): CallDataInterface
{
return new BridgeCallData(
$this->name,
$this->arguments,
);
}
}
10 changes: 8 additions & 2 deletions src/VM/Core/Runtime/Executor/Accessor/ContextAccessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,20 @@ public function __call(string $name, array $arguments): mixed
{
$self = $this->executedResult->executor->context()->self();

$arguments = array_map(
static fn ($value) => Translator::PHPToRuby($value),
$arguments,
);

/**
* @var ExecutedResult $executedResult
*/
$executedResult = $self->{$name}(
...array_map(
static fn ($value) => Translator::PHPToRuby($value),
new BridgeCallInfo(
$name,
$arguments,
),
...$arguments,
);
if ($executedResult->threw instanceof \Throwable) {
throw $executedResult->threw;
Expand Down
14 changes: 4 additions & 10 deletions src/VM/Core/Runtime/Executor/CallBlockHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

trait CallBlockHelper
{
private function callSimpleMethod(ContextInterface $context, RubyClassInterface|ContextInterface ...$arguments): ExecutedResult
private function callSimpleMethod(ContextInterface $context, CallInfoInterface $callInfo, RubyClassInterface|ContextInterface ...$arguments): ExecutedResult
{
// Validate first value is context?
$calleeContexts = [];
Expand All @@ -45,13 +45,6 @@ private function callSimpleMethod(ContextInterface $context, RubyClassInterface|
->body()
->info();

$currentCallInfo = $context
->parentContext()
?->instructionSequence()
->body()
->info()
->currentCallInfo();

$localTableSize = $iseqBodyData
->localTableSize();

Expand All @@ -71,14 +64,14 @@ private function callSimpleMethod(ContextInterface $context, RubyClassInterface|
$startOfSplat = count($arguments) - $restStart;

$arguments = self::alignArguments(
$currentCallInfo,
$callInfo,
$executor->context(),
array_reverse(array_slice($arguments, 0, $startOfSplat)),
...array_slice($arguments, $startOfSplat),
);
} else {
$arguments = self::alignArguments(
$currentCallInfo,
$callInfo,
$executor->context(),
...$arguments,
);
Expand Down Expand Up @@ -152,6 +145,7 @@ private function callBlockWithArguments(CallInfoInterface $callInfo, Number $blo
->setRuntimeContext($executor->context())
->setUserlandHeapSpace($executor->context()->self()->userlandHeapSpace())
->{(string) $callInfo->callData()->mid()->object}(
$callInfo,
$executor->context(),
...self::alignArguments(
$callInfo,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public function process(ContextInterface|RubyClassInterface ...$arguments): Proc
$executed = $this
->callSimpleMethod(
$processorContext,
$operand,
...$arguments,
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,6 @@ public function process(ContextInterface|RubyClassInterface ...$arguments): Proc

$targetClass->setRuntimeContext($this->context);

// Set current call info into instruction sequence
$this->context
->instructionSequence()
->body()
->info()
->setCurrentCallInfo($callInfo);

$result = null;

// Here is a special method calls
Expand All @@ -101,14 +94,18 @@ public function process(ContextInterface|RubyClassInterface ...$arguments): Proc
$result = $calleeSpecialMethodName->process(
$targetClass,
$this->context,
$callInfo,
...$this->translateForArguments(...$arguments),
);
} else {
/**
* @var null|ExecutedResult|RubyClassInterface $result
*/
$result = $targetClass
->{(string) $symbol}(...$this->translateForArguments(...$arguments));
->{(string) $symbol}(
$callInfo,
...$this->translateForArguments(...$arguments),
);
}

if ($result instanceof RubyClassInterface) {
Expand Down
3 changes: 2 additions & 1 deletion src/VM/Core/Runtime/Executor/SpecialMethod/Initialize.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@
use RubyVM\VM\Core\Runtime\Essential\RubyClassInterface;
use RubyVM\VM\Core\Runtime\Executor\Context\ContextInterface;
use RubyVM\VM\Core\Runtime\Executor\Operation\Operand;
use RubyVM\VM\Core\YARV\Criterion\InstructionSequence\CallInfoInterface;

class Initialize implements SpecialMethodInterface
{
public function process(RubyClassInterface $class, ContextInterface $context, mixed ...$arguments): mixed
public function process(RubyClassInterface $class, ContextInterface $context, CallInfoInterface $callInfo, mixed ...$arguments): mixed
{
$result = $class;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@

use RubyVM\VM\Core\Runtime\Essential\RubyClassInterface;
use RubyVM\VM\Core\Runtime\Executor\Context\ContextInterface;
use RubyVM\VM\Core\YARV\Criterion\InstructionSequence\CallInfoInterface;

interface SpecialMethodInterface
{
public function process(RubyClassInterface $class, ContextInterface $context, mixed ...$arguments): mixed;
public function process(RubyClassInterface $class, ContextInterface $context, CallInfoInterface $callInfo, mixed ...$arguments): mixed;
}
3 changes: 2 additions & 1 deletion src/VM/Core/Runtime/Lambda.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use RubyVM\VM\Core\Runtime\Essential\MainInterface;
use RubyVM\VM\Core\Runtime\Essential\RubyClassInterface;
use RubyVM\VM\Core\Runtime\Executor\Executor;
use RubyVM\VM\Core\YARV\Criterion\InstructionSequence\CallInfoInterface;
use RubyVM\VM\Core\YARV\Criterion\InstructionSequence\InstructionSequenceInterface;
use RubyVM\VM\Core\YARV\Criterion\ShouldBeRubyClass;
use RubyVM\VM\Core\YARV\Essential\Symbol\StringSymbol;
Expand All @@ -31,7 +32,7 @@ public function __toString(): string
return 'lambda';
}

public function call(RubyClassInterface ...$arguments): RubyClassInterface|null
public function call(CallInfoInterface $callInfo, RubyClassInterface ...$arguments): RubyClassInterface|null
{
$executor = new Executor(
kernel: $this->context()->kernel(),
Expand Down
7 changes: 4 additions & 3 deletions src/VM/Core/Runtime/Provider/ProvideBasicClassMethods.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@
use RubyVM\VM\Core\Runtime\Executor\Context\ContextInterface;
use RubyVM\VM\Core\Runtime\Lambda;
use RubyVM\VM\Core\Runtime\UserlandHeapSpace;
use RubyVM\VM\Core\YARV\Criterion\InstructionSequence\CallInfoInterface;
use RubyVM\VM\Core\YARV\Essential\Symbol\ArraySymbol;
use RubyVM\VM\Core\YARV\Essential\Symbol\NilSymbol;
use RubyVM\VM\Core\YARV\Essential\Symbol\RangeSymbol;
use RubyVM\VM\Core\YARV\Essential\Symbol\StringSymbol;

trait ProvideBasicClassMethods
{
public function puts(RubyClassInterface $object): RubyClassInterface
public function puts(CallInfoInterface $callInfo, RubyClassInterface $object): RubyClassInterface
{
$symbol = $object->entity()->symbol();

Expand All @@ -44,7 +45,7 @@ public function puts(RubyClassInterface $object): RubyClassInterface
->toBeRubyClass();
}

public function exit(int $code = 0): never
public function exit(CallInfoInterface $callInfo, int $code = 0): never
{
exit($code);
}
Expand All @@ -60,7 +61,7 @@ public function inspect(): RubyClassInterface
->toBeRubyClass();
}

public function lambda(ContextInterface $context): RubyClassInterface
public function lambda(CallInfoInterface $callInfo, ContextInterface $context): RubyClassInterface
{
return (new Lambda($context->instructionSequence()))
->setRuntimeContext($this->context())
Expand Down
11 changes: 10 additions & 1 deletion src/VM/Core/Runtime/Provider/ProvideExtendedMethodCall.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
use RubyVM\VM\Core\Runtime\Executor\Context\ContextInterface;
use RubyVM\VM\Core\Runtime\Executor\ExecutedResult;
use RubyVM\VM\Core\Runtime\RubyClass;
use RubyVM\VM\Core\YARV\Criterion\InstructionSequence\CallInfoInterface;
use RubyVM\VM\Exception\NotFoundInstanceMethod;
use RubyVM\VM\Exception\OperationProcessorException;
use RubyVM\VM\Exception\RuntimeException;

trait ProvideExtendedMethodCall
{
Expand Down Expand Up @@ -52,10 +54,17 @@ public function __call(string $name, array $arguments): ExecutedResult|RubyClass
return $this->__call($context, $arguments);
}

if (($arguments[0] ?? null) !== null && !$arguments[0] instanceof CallInfoInterface) {
throw new RuntimeException('A CallInfo entry was not passed');
}

return $this
->callSimpleMethod(
$context,
...$arguments,

// @phpstan-ignore-next-line
$arguments[0],
...array_slice($arguments, 1),
);
}

Expand Down
Loading

0 comments on commit 350c865

Please sign in to comment.