An open API service indexing awesome lists of open source software.

https://github.com/eventjet/ausdruck

A small generic expression engine for PHP
https://github.com/eventjet/ausdruck

expressionengine hacktoberfest php

Last synced: about 1 month ago
JSON representation

A small generic expression engine for PHP

Awesome Lists containing this project

README

          

# Ausdruck

A small expression engine for PHP.

## Quick start

```
composer require eventjet/ausdruck
```

```php
use Eventjet\Ausdruck\Parser\ExpressionParser;
use Eventjet\Ausdruck\Parser\Types;
use Eventjet\Ausdruck\Type;

$expression = ExpressionParser::parse(
'joe:MyPersonType.name:string()',
new Types(['MyPersonType' => Type::listOf(Type::string())]),
);
$scope = new Scope(
// Passing values to the expression
['joe' => ['joe']],
// Custom function definitions
['name' => static fn (array $person): string => $person[0]],
);
$name = $expression->evaluate($scope);
assert($name === 'Joe');
```

## Documentation

### Accessing scope variables

Syntax: `varName:type`

Scope variables are passed from PHP when it calls `evaluate()` on the expression:

```php
use Eventjet\Ausdruck\Parser\ExpressionParser;
use Eventjet\Ausdruck\Scope;

$x = ExpressionParser::parse('foo:int')
->evaluate(new Scope(['foo' => 123]));
assert($x === 123);
```

#### Examples

`foo:int`, `foo:list`

See [Types](#types)

### Literals

- `123`: Integer
- `"foo"`: String
- `1.23`: Float
- `[1, myInt:int, 3]`: List of integers
- `["foo", myString:string, "bar"]`: List of strings

### Operators

Both operands must be of the same type.

| Operator | Description | Example | Note |
|----------|--------------|--------------------------|-------------------------------------------|
| `===` | Equality | `foo:string === "bar"` | |
| `-` | Subtraction | `foo:int - bar:int` | Operands must be of type `int` or `float` |
| `>` | Greater than | `foo:int > bar:int` | Operands must be of type `int` or `float` |
| `\|\|` | Logical OR | `foo:bool \|\| bar:bool` | Operands must be of type `bool` |
| && | Logical AND | `foo:bool && bar:bool` | Operands must be of type `bool` |

Where's the rest? We're implementing more as we need them.

### Types

The following types are supported:

- `int`: Integer
- `string`: String
- `bool`: Boolean
- `float`: Floating point number
- `list`: List of type T
- `map`: Map with key type K and value type V
- Any other type will be treated as an alias that you will have to provide when parsing the expression:
```php
use Eventjet\Ausdruck\Parser\ExpressionParser;
use Eventjet\Ausdruck\Type;

ExpressionParser::parse('foo:MyType', ['MyType' => Type::alias(Type::listOf(Type::string()))]);
```

### Functions

Syntax: `target.functionName:returnType(arg1, arg2, ...)`

The target can be any expression. It will be passed as the first argument to the function.

#### Example

`haystack:list.contains:bool(needle:string)`

#### Built-In Functions

| Function | Description | Example |
|------------|------------------------------------------------------------------------|--------------------------------------------------|
| `count` | Returns the number of elements in a list | `foo:list.count:int()` |
| `contains` | Returns whether a list contains a value | `foo:list.contains:bool("bar")` |
| `head` | Returns the first element of a list as an `Option` | `foo:list.head:Option()` |
| `isSome` | Takes an Option and returns whether it is `Some` | `foo:Option.isSome:bool()` |
| `map` | Returns a new list with the results of applying a [function](#lambdas) | `foo:list.map:list(\|i\| i:int - 2)` |
| `some` | Returns whether any element matches a [predicate](#lambdas) | `foo:list.some:bool(\|item\| item:int > 5)` |
| `substr` | Returns a substring of a string | `foo:string.substr:string(0, 5)` |
| `tail` | Returns all elements of a list except the first | `foo:list.tail:list()` |
| `take` | Returns the first n elements of a list | `foo:list.take:list(5)` |
| `unique` | Returns a list with duplicate elements removed | `foo:list.unique:list()` |

#### Custom Functions

You can pass custom functions along with the scope variables:

```php
use Eventjet\Ausdruck\Parser\ExpressionParser;use Eventjet\Ausdruck\Scope;

$scope = new Scope(
['foo' => 'My secret'],
['mask' => fn (string $str, string $mask) => str_repeat($mask, strlen($str))]
);
$result = ExpressionParser::parse('foo:string.mask("x")')->evaluate($scope);
assert($result === 'xxxxxxxxx');
```

The target of the function/method call (`foo:string` in the example above) will be passed as the first argument to the
function.

### Lambdas

Syntax: `|arg1, arg2, ... | expression`

To access an argument, you must specify its type, just like when accessing scope variables.

#### Example

`|item| item:int > 5`