klitsche/ffigen

View on GitHub
src/Adapter/PHPCParser/DefinesCollector.php

Summary

Maintainability
B
4 hrs
Test Coverage
A
92%
<?php

declare(strict_types=1);

namespace Klitsche\FFIGen\Adapter\PHPCParser;

use Klitsche\FFIGen\Define;
use Klitsche\FFIGen\DefinesCollection;
use Klitsche\FFIGen\Types\Builtin;
use PHPCParser\PreProcessor\Token;

class DefinesCollector
{
    private const PHPCPARSER_BUILT_IN_FILE = 'built-in';

    private ValueEvaluator $evaluator;

    public function __construct(?ValueEvaluator $evaluator = null)
    {
        $this->evaluator = $evaluator ?? new ValueEvaluator();
    }

    /**
     * @param Token[] $defineTokens
     */
    public function collect(array $defineTokens): DefinesCollection
    {
        $defines = [];
        foreach ($defineTokens as $identifier => $token) {
            if ($token === null) {
                continue;
            }
            if ($token->file === self::PHPCPARSER_BUILT_IN_FILE) {
                continue;
            }
            $value = '';
            $next = $token;
            do {
                if ($next instanceof Token && $next->type === Token::IDENTIFIER) {
                    // cast basic types, eg ((int32_t)-1) => ((int)-1)
                    if (Builtin::isMappable($next->value)) {
                        $value .= Builtin::map($next->value);
                    } else {
                        continue 2;
                    }
                } elseif ($next instanceof Token && $next->type === Token::LITERAL) {
                    continue 2;
                } elseif ($next instanceof Token && $next->type !== Token::WHITESPACE) {
                    $value .= $next->value;
                }
                $next = $next->next;
            } while ($next !== null);

            $value = $this->evaluator->evalulate($value);
            if ($value !== null) {
                $defines[] = new Define($identifier, $value);
            }
        }

        return new DefinesCollection(...$defines);
    }
}