Skip to content

Commit

Permalink
Refactor Runtime Type Checks to Utilize Value-Derived Type Validation (
Browse files Browse the repository at this point in the history
…#26)

This refactor introduces a significant change to the runtime type checking mechanism across the codebase. Previously, each type had an associated assertion function responsible for validating its values. The new implementation shifts this responsibility to a more dynamic approach where the type is deduced directly from the value, and then it is validated to determine if it is a subtype of the expected type.

Key changes include:

- Elimination of the `Assert` class: The dedicated assertion functions have been removed, as the logic for type validation is now incorporated within the `Type` class and related expressions.
- Improved Error Handling: The error messages generated during evaluation now reflect the exact types encountered, providing clearer feedback on type-related issues.
  • Loading branch information
MidnightDesign authored Aug 15, 2024
1 parent cd5d8f2 commit ec579eb
Show file tree
Hide file tree
Showing 25 changed files with 197 additions and 595 deletions.
16 changes: 10 additions & 6 deletions src/And_.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,16 @@

use Eventjet\Ausdruck\Parser\Span;

use function get_debug_type;
use function is_bool;
use function sprintf;

/**
* @extends Expression<bool>
* @internal
* @psalm-internal Eventjet\Ausdruck
*/
final class And_ extends Expression
{
/**
* @param Expression<bool> $left
* @param Expression<bool> $right
*/
public function __construct(public readonly Expression $left, public readonly Expression $right)
{
}
Expand All @@ -31,7 +28,14 @@ public function __toString(): string

public function evaluate(Scope $scope): bool
{
return $this->left->evaluate($scope) && $this->right->evaluate($scope);
$left = $this->left->evaluate($scope);
$right = $this->right->evaluate($scope);
if (!is_bool($left) || !is_bool($right)) {
throw new EvaluationError(
sprintf('Expected boolean operands, got %s and %s', get_debug_type($left), get_debug_type($right)),
);
}
return $left && $right;
}

public function equals(Expression $other): bool
Expand Down
172 changes: 0 additions & 172 deletions src/Assert.php

This file was deleted.

10 changes: 3 additions & 7 deletions src/Call.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
use function sprintf;

/**
* @template T
* @extends Expression<T>
* @internal
* @psalm-internal Eventjet\Ausdruck
*/
Expand All @@ -24,9 +22,7 @@ final class Call extends Expression
use LocationTrait;

/**
* @param Expression<mixed> $target
* @param list<Expression<mixed>> $arguments
* @param Type<T> $type
* @param list<Expression> $arguments
*/
public function __construct(
public readonly Expression $target,
Expand All @@ -39,8 +35,8 @@ public function __construct(
}

/**
* @param list<Expression<mixed>> $a
* @param list<Expression<mixed>> $b
* @param list<Expression> $a
* @param list<Expression> $b
*/
private static function compareArguments(array $a, array $b): bool
{
Expand Down
5 changes: 0 additions & 5 deletions src/Eq.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,11 @@
use function sprintf;

/**
* @extends Expression<bool>
* @internal
* @psalm-internal Eventjet\Ausdruck
*/
final class Eq extends Expression
{
/**
* @param Expression<mixed> $left
* @param Expression<mixed> $right
*/
public function __construct(public readonly Expression $left, public readonly Expression $right)
{
}
Expand Down
53 changes: 4 additions & 49 deletions src/Expr.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,84 +22,56 @@ private function __construct()
{
}

/**
* @template T
* @param Expression<T> $left
* @param Expression<T> $right
*/
public static function eq(Expression $left, Expression $right): Eq
{
return new Eq($left, $right);
}

/**
* @template T
* @param Type<T> | class-string<T> | TypeHint<T> $type
* @return Get<T>
* @param Type | class-string | TypeHint $type
*/
public static function get(string $name, TypeHint|Type|string $type, Span|null $location = null): Get
{
/** @phpstan-ignore-next-line Must be a PHPStan bug */
$type = is_string($type) ? Type::object($type) : $type;
/** @phpstan-ignore-next-line False positive */
return new Get($name, $type, $location ?? self::dummySpan());
}

/**
* @template T of string | int | float | bool | null | array<array-key, mixed>
* @param T $value
* @return Literal<T>
* @param string | int | float | bool | null | array<array-key, mixed> $value
*/
public static function literal(mixed $value, Span|null $location = null): Literal
{
return new Literal($value, $location ?? self::dummySpan());
}

/**
* @template T
* @param list<Expression<T>> $elements
* @return ListLiteral<T>
* @param list<Expression> $elements
*/
public static function listLiteral(array $elements, Span $location): ListLiteral
{
return new ListLiteral($elements, $location);
}

/**
* @template T
* @param Expression<mixed> $target
* @param list<Expression<mixed>> $arguments
* @param Type<T> $type
* @return Call<T>
* @param list<Expression> $arguments
*/
public static function call(Expression $target, string $name, Type $type, array $arguments, Span|null $location = null): Call
{
return new Call($target, $name, $type, $arguments, $location ?? self::dummySpan());
}

/**
* @param Expression<bool> $left
* @param Expression<bool> $right
*/
public static function or_(Expression $left, Expression $right): Or_
{
return new Or_($left, $right);
}

/**
* @param Expression<bool> $left
* @param Expression<bool> $right
*/
public static function and_(Expression $left, Expression $right): And_
{
return new And_($left, $right);
}

/**
* @template T
* @param Expression<T> $body
* @param list<string> $parameters
* @return Expression<callable(Scope): T>
*/
public static function lambda(Expression $body, array $parameters = [], Span|null $location = null): Expression
{
Expand All @@ -108,33 +80,16 @@ public static function lambda(Expression $body, array $parameters = [], Span|nul
return new Lambda($body, $parameters, $location);
}

/**
* @template T of int | float
* @param Expression<T> $minuend
* @param Expression<T> $subtrahend
* @return Subtract<T>
*/
public static function subtract(Expression $minuend, Expression $subtrahend): Subtract
{
return new Subtract($minuend, $subtrahend);
}

/**
* @template T of int | float
* @param Expression<T> $left
* @param Expression<T> $right
* @return Gt<T>
*/
public static function gt(Expression $left, Expression $right): Gt
{
return new Gt($left, $right);
}

/**
* @template T of int | float
* @param Expression<T> $expression
* @return Negative<T>
*/
public static function negative(Expression $expression, Span|null $location = null): Negative
{
return new Negative($expression, $location ?? self::dummySpan());
Expand Down
Loading

0 comments on commit ec579eb

Please sign in to comment.