PHP code example of gosuperscript / axiom

1. Go to this page and download the library: Download gosuperscript/axiom library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

gosuperscript / axiom example snippets


use Superscript\Axiom\Expression;
use Superscript\Axiom\Sources\Coerce;
use Superscript\Axiom\Sources\StaticSource;
use Superscript\Axiom\Types\NumberType;

$source = new Coerce(
    type: new NumberType(),
    source: new StaticSource('42'),
);

$program = (new Expression($source))->compile()->unwrap();

$program()->unwrap()->unwrap(); // 42 (as integer)

use Superscript\Axiom\Definitions;
use Superscript\Axiom\Expression;
use Superscript\Axiom\ReferencePath;
use Superscript\Axiom\Sources\InfixExpression;
use Superscript\Axiom\Sources\StaticSource;
use Superscript\Axiom\Types\NumberType;
use Superscript\Axiom\Types\RecordType;

// area = PI * radius * radius
$source = new InfixExpression(
    left: new ReferencePath('PI'),
    operator: '*',
    right: new InfixExpression(
        left: new ReferencePath('radius'),
        operator: '*',
        right: new ReferencePath('radius'),
    ),
);

$area = new Expression(
    source: $source,
    definitions: new Definitions(['PI' => new StaticSource(3.14159)]),
    declarations: new RecordType(['radius' => new NumberType()]),
);

$area->parameters(); // ['radius']

$program = $area->compile()->unwrap();  // every node resolved and certified
$program->returns;                      // NumberType — a property, not a query
$program->references;                   // [new ReferencePath('radius')]

$program(['radius' => 5])->unwrap()->unwrap();  // ~78.54
$program(['radius' => 10])->unwrap()->unwrap(); // ~314.16

$program = $expression->compile()->unwrap();

$program->returns;    // the inferred return type
$program->references; // declared inputs resolved by compilation
$program($bindings);  // boundary + evaluation; Result<Option<mixed>, Throwable>

$gate->infer();                  // Ok(BooleanType) — what does this return?
$gate->check(new BooleanType()); // certified

$diagnosis = $expression->diagnose();

$diagnosis->diagnostics; // list<TypeMismatch> — every refusal, in the order compilation met them
$diagnosis->references;  // list<ReferencePath>, including unresolved reads
$diagnosis->returns;     // the root type, or null where the root itself failed
$diagnosis->program();   // Ok(Program) iff there are no diagnostics

$program = $expression->compile()->unwrap();
$analysis = $program->analysis;

$analysis->root;        // typed CompilationNode tree
$analysis->operators(); // selected rules with deterministic source paths
$analysis->toArray();   // serializable export

$sameAnalysis = $expression->analyze()->unwrap();

use Superscript\Axiom\Expression;
use Superscript\Axiom\ReferencePath;
use Superscript\Axiom\Sources\InfixExpression;
use Superscript\Axiom\Sources\StaticSource;
use Superscript\Axiom\Types\NumberType;
use Superscript\Axiom\Types\Optional;
use Superscript\Axiom\Types\OptionType;
use Superscript\Axiom\Types\RecordType;
use Superscript\Axiom\Types\StringType;

$turnover = new ReferencePath('customer', 'turnover');
$condition = new InfixExpression(
    left: new InfixExpression($turnover, '*', new StaticSource(1.2)),
    operator: '>',
    right: new StaticSource(500000),
);

$gate = new Expression(
    source: $condition,
    definitions: $definitions,
    declarations: new RecordType([
        'customer' => new RecordType([
            'turnover' => new NumberType(),
        ]),
    ]),
);

$program = $gate->compile()->unwrap();

$program(['customer' => ['turnover' => '600000']]);
// the BOUNDARY coerces '600000' → 600000 through the declared type
// before evaluation — certified programs never see raw garbage

$program(['customer' => ['turnover' => 'lots']]);
// Err(InadmissibleBinding): "binding [customer]: Property [turnover]: …"
// — aggregated and named before any evaluation

$program([]);
// Err(MissingRequiredInput): the customer root 

declarations: new RecordType([
    'excess' => new OptionType($monetary),
    'comment' => new Optional(new StringType()),
])

$program([]);                  // Err(MissingRequiredInput): nobody has answered
$program(['excess' => null]);  // Ok(None): answered, and the answer is "none"
$program(['excess' => '250']); // Ok(Some(250))

$failure = $expression->compile()->unwrapErr(); // (name + 1) * 2, name declared String

$failure->message; // '[+] expects Number and Number; got String and 1.'
$failure->path;    // '$.children[0].node' — the inner +, not the outer *

  $tier = new UnionType(new LiteralType('micro'), new LiteralType('small'));
  $tier->assert('micro'); // Ok(Some('micro'))
  $tier->assert('large'); // Err — not a member
  

$numberType = new NumberType();

$numberType->assert(42);     // Ok(Some(42))
$numberType->assert('42');   // Err(TransformValueException)

$numberType->coerce(42);     // Ok(Some(42))
$numberType->coerce('42');   // Ok(Some(42))
$numberType->coerce('45%');  // Ok(Some(0.45))

new Coerce(new NumberType(), $rawLookupCell)   // '42 ' → 42; the compiler takes Number on faith

new Ascription(new NumberType(), $unknownHostSource)  // "trust me, this is a number" — and it's checked twice

new DefaultValue($optionalPremium, 0)
new DefaultValue($optionalTags, [])

new InfixExpression($optionalPremium, '??', new ReferencePath('standard_premium'))

use Superscript\Axiom\Definitions;
use Superscript\Axiom\Expression;
use Superscript\Axiom\ReferencePath;
use Superscript\Axiom\Sources\StaticSource;
use Superscript\Axiom\Types\NumberType;
use Superscript\Axiom\Types\Optional;
use Superscript\Axiom\Types\RecordType;

$expression = new Expression(
    source: new ReferencePath('quote', 'turnover'),
    definitions: new Definitions([
        'version' => new StaticSource('1.0.0'),
    ]),
    declarations: new RecordType([
        'quote' => new RecordType([
            'turnover' => new NumberType(),
            'claims' => new Optional(new NumberType()),
        ]),
    ]),
);

$program = $expression->compile()->unwrap();
$program([
    'quote' => [
        'turnover' => 600000,
        // 'claims' may be omitted
    ],
]);

// if quote.claims > 2 then 100 * 0.25 else 0
new MatchExpression(
    subject: new StaticSource(true),
    arms: [
        new MatchArm(
            new ExpressionPattern(
                new InfixExpression(
                    new ReferencePath('quote', 'claims'),
                    '>',
                    new StaticSource(2),
                ),
            ),
            new InfixExpression(new StaticSource(100), '*', new StaticSource(0.25)),
        ),
        new MatchArm(new WildcardPattern(), new StaticSource(0)),
    ],
);

// match tier { "micro" => 1.3, "small" => 1.1, _ => 1.0 }
new MatchExpression(
    subject: new ReferencePath('tier'),
    arms: [
        new MatchArm(new LiteralPattern('micro'), new StaticSource(1.3)),
        new MatchArm(new LiteralPattern('small'), new StaticSource(1.1)),
        new MatchArm(new WildcardPattern(), new StaticSource(1.0)),
    ],
);

use Superscript\Axiom\Execution\Annotated;
use Superscript\Axiom\Execution\Event;
use Superscript\Axiom\Execution\Observer;

final class AnnotationLog implements Observer
{
    public array $annotations = [];

    public function observe(Event $event): void
    {
        if ($event instanceof Annotated) {
            $this->annotations[] = [
                'source' => $event->node->sourceType,
                'key' => $event->key,
                'value' => $event->value,
            ];
        }
    }
}

$observer = new AnnotationLog();
$program = $expression->compile()->unwrap();
$result = $program->call(['radius' => 5], observer: $observer);

use Superscript\Axiom\Operators\Operator;

Operator::infix('-')
    ->identifiedBy('time.date.minus-period')
    ->takes(new DateType(), new PeriodType())
    ->returns(new DateType())
    ->evaluatesWith(fn (Date $d, Period $p) => $d->minus($p));