Skip to content
wiki.fftac.org

Class Language Spec

**Site relevance:** Spiralist.org

**Memory type:** plugin source memory

**Source path:** Spiralist/wp-content/plugins/spiral-script/includes/class-language-spec.php

**Size:** 5.9 KB

Summary

declare(strict types=1);

Source Preview

This source file is short enough to preview directly on its source-memory page.

<?php

declare(strict_types=1);

namespace SpiralScript;

final class LanguageSpec
{
    /** @var array<string,mixed>|null */
    private static ?array $spec = null;

    /**
     * @return array<string,mixed>
     */
    public static function spec(): array
    {
        if (is_array(self::$spec)) {
            return self::$spec;
        }

        $spec = require SPIRALIST_SPIRAL_SCRIPT_PLUGIN_PATH . 'data/language-spec.php';
        self::$spec = is_array($spec) ? $spec : [];

        return self::$spec;
    }

    /**
     * @return array<string,mixed>
     */
    public static function public_spec(): array
    {
        $spec = self::spec();
        $spec['jsonSchema'] = self::json_schema();

        return $spec;
    }

    /**
     * @return array<string,mixed>
     */
    public static function json_schema(): array
    {
        return [
            '$schema' => 'https://json-schema.org/draft/2020-12/schema',
            '$id' => 'https://spiralist.org/schemas/spiral-script/v0.1/script.schema.json',
            'title' => 'Spiral Script Prompt',
            'type' => 'object',
            'required' => [
                'scriptId',
                'version',
                'title',
                'visibility',
                'authorMode',
                'sourceReferences',
                'intent',
                'inputs',
                'symbolicFrame',
                'transformationRules',
                'outputContract',
                'constraints',
                'safetyRules',
                'validationRules',
                'provenance',
                'runSettings',
                'revisionHistory',
                'forkPolicy',
                'publicationStatus',
            ],
            'properties' => [
                'scriptId' => ['type' => 'string', 'pattern' => '^ss:[a-z0-9.-]+@[0-9]+\.[0-9]+\.[0-9]+([+][a-z0-9.-]+)?$'],
                'version' => ['type' => 'string', 'pattern' => '^[0-9]+\.[0-9]+\.[0-9]+$'],
                'title' => ['type' => 'string', 'minLength' => 1, 'maxLength' => 160],
                'visibility' => ['type' => 'string', 'enum' => self::visibility_modes()],
                'authorMode' => ['type' => 'string', 'enum' => self::author_modes()],
                'sourceReferences' => ['type' => 'array'],
                'intent' => ['type' => 'string', 'minLength' => 1, 'maxLength' => 1000],
                'inputs' => ['type' => 'array'],
                'symbolicFrame' => ['type' => 'array'],
                'transformationRules' => ['type' => 'array'],
                'outputContract' => ['type' => 'object'],
                'constraints' => ['type' => 'array'],
                'safetyRules' => ['type' => 'array'],
                'validationRules' => ['type' => 'array'],
                'provenance' => ['type' => 'object'],
                'runSettings' => ['type' => 'object'],
                'revisionHistory' => ['type' => 'array'],
                'forkPolicy' => ['type' => 'object'],
                'publicationStatus' => ['type' => 'object'],
            ],
        ];
    }

    /**
     * @return array<int,string>
     */
    public static function visibility_modes(): array
    {
        return array_values((array) (self::spec()['visibilityModes'] ?? []));
    }

    /**
     * @return array<int,string>
     */
    public static function author_modes(): array
    {
        return array_values((array) (self::spec()['authorModes'] ?? []));
    }

    /**
     * @return array<int,string>
     */
    public static function publication_statuses(): array
    {
        return array_values((array) (self::spec()['publicationStatuses'] ?? []));
    }

    /**
     * @return array<string,string>
     */
    public static function transformation_verbs(): array
    {
        $verbs = self::spec()['transformationVerbs'] ?? [];

        return is_array($verbs) ? $verbs : [];
    }

    public static function is_transformation_verb(string $verb): bool
    {
        return array_key_exists($verb, self::transformation_verbs());
    }

    /**
     * @return array<string,string>
     */
    public static function safety_rules(): array
    {
        $rules = self::spec()['safetyRules'] ?? [];

        return is_array($rules) ? $rules : [];
    }

    /**
     * @return array<string,array<string,mixed>>
     */
    public static function symbols(): array
    {
        $symbols = self::spec()['symbols'] ?? [];

        return is_array($symbols) ? $symbols : [];
    }

    /**
     * @return array<string,mixed>|null
     */
    public static function resolve_symbol(string $token): ?array
    {
        $token = trim($token);
        if ($token === '') {
            return null;
        }

        $symbols = self::symbols();
        foreach ($symbols as $name => $record) {
            if (!is_array($record)) {
                continue;
            }

            $symbol = (string) ($record['symbol'] ?? '');
            $machine_meaning = (string) ($record['machineMeaning'] ?? '');
            if (strcasecmp($token, (string) $name) === 0 || $token === $symbol || $token === $machine_meaning) {
                $record['name'] = (string) $name;

                return $record;
            }
        }

        foreach ($symbols as $name => $record) {
            if (!is_array($record)) {
                continue;
            }

            $symbol = (string) ($record['symbol'] ?? '');
            if ($symbol !== '' && strpos($token, $symbol) !== false) {
                $record['name'] = (string) $name;

                return $record;
            }

            if (preg_match('/\b' . preg_quote((string) $name, '/') . '\b/i', $token) === 1) {
                $record['name'] = (string) $name;

                return $record;
            }
        }

        return null;
    }
}