Skip to content

Commit

Permalink
Added Go support (#118)
Browse files Browse the repository at this point in the history
Added Go support
  • Loading branch information
KoNekoD authored Apr 19, 2024
1 parent 7840d75 commit a6d4c9b
Show file tree
Hide file tree
Showing 27 changed files with 1,850 additions and 41 deletions.
491 changes: 491 additions & 0 deletions .editorconfig

Large diffs are not rendered by default.

19 changes: 19 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
COMPOSE_FILE = ./docker/docker-compose.yml
DOCKER_COMPOSE = docker compose -f ${COMPOSE_FILE}
DOCKER_COMPOSE_PHP_FPM_EXEC = ${DOCKER_COMPOSE} exec php-converter

build:
${DOCKER_COMPOSE} build

up:
${DOCKER_COMPOSE} up -d --remove-orphans

down:
${DOCKER_COMPOSE} down -v

down_force:
${DOCKER_COMPOSE} down -v --rmi=all --remove-orphans

console:
if ! ${DOCKER_COMPOSE} ps | grep -q raphael-php-fpm; then make up; fi
${DOCKER_COMPOSE_PHP_FPM_EXEC} bash
35 changes: 35 additions & 0 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
FROM php:8.3-fpm-alpine as php-converter

ARG SCRIPT_URL='https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions'
RUN set -eux && \
curl -sSLf -o /usr/local/bin/install-php-extensions ${SCRIPT_URL} && \
chmod +x /usr/local/bin/install-php-extensions && \
apk add git bash gettext openssh && \
touch /var/log/xdebug.log && chmod 0666 /var/log/xdebug.log && \
install-php-extensions @composer intl zip opcache pcntl sockets xsl

ARG PHP_IDE_CONFIG="serverName=Docker"
ENV PHP_IDE_CONFIG=$PHP_IDE_CONFIG
ARG XDEBUG_AUTOSTART=trigger
ARG DEV_HOST_IP=172.18.7.1
ARG DEV_XDEBUG_IDE_KEY=PHPSTORM
ARG XDEBUG_FILE=/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
RUN install-php-extensions xdebug gd && \
echo "xdebug.mode=debug" >> $XDEBUG_FILE && \
echo "xdebug.start_with_request=$XDEBUG_AUTOSTART" >> $XDEBUG_FILE && \
echo "xdebug.client_host=$DEV_HOST_IP" >> $XDEBUG_FILE && \
echo "xdebug.client_port=9003" >> $XDEBUG_FILE && \
echo "xdebug.log=/var/log/xdebug.log" >> $XDEBUG_FILE && \
echo "xdebug.idekey=$DEV_XDEBUG_IDE_KEY" >> $XDEBUG_FILE && \
apk add --no-cache ranger vim nano vifm;

COPY --from=cytopia/gofmt:latest /usr/local/bin/gofmt /usr/bin/gofmt
COPY ./docker/memory_limit.ini /usr/local/etc/php/conf.d/memory_limit.ini

ARG UID=1000
ARG GID=1000
RUN addgroup -g $GID app && adduser -D -u $UID -G app app && addgroup app www-data
USER app
COPY --chown=app:app ../ /var/www/php-converter
WORKDIR /var/www/php-converter
USER www-data
14 changes: 13 additions & 1 deletion docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,19 @@ name: php-converter
services:
php-converter:
container_name: php-converter
user: app
build:
context: ./php
dockerfile: ./docker/Dockerfile
context: ../
volumes:
- ../.:/var/www/php-converter:cached
networks:
- php-converter-network

networks:
php-converter-network:
name: php-converter-network
ipam:
config:
- subnet: 172.18.7.0/24
gateway: 172.18.7.1
1 change: 1 addition & 0 deletions docker/memory_limit.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
memory_limit = 1G
14 changes: 0 additions & 14 deletions docker/php/Dockerfile

This file was deleted.

18 changes: 0 additions & 18 deletions docker/php/php.ini

This file was deleted.

4 changes: 2 additions & 2 deletions src/OutputGenerator/Dart/DartOutputGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ public function __construct(
}

/** @return OutputFile[] */
public function generate(ConverterResult $converterResult): array
public function generate(ConverterResult $result): array
{
$this->outputWriter->reset();

$dtoList = $converterResult->dtoList;
$dtoList = $result->dtoList;
foreach ($dtoList->getList() as $dto) {
$this->outputWriter->writeType($this->convertToDartType($dto, $dtoList), $dto);
}
Expand Down
68 changes: 68 additions & 0 deletions src/OutputGenerator/Go/GoEnumResolver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php

declare(strict_types=1);

namespace Riverwaysoft\PhpConverter\OutputGenerator\Go;

use Exception;
use Riverwaysoft\PhpConverter\Dto\DtoEnumProperty;
use Riverwaysoft\PhpConverter\Dto\DtoType;

class GoEnumResolver
{
/** @var string[] */
private array $usedConstantsStore = [];

/** @throws Exception */
public function resolve(DtoType $dto): string
{
$firstEnumProperty = $dto->getProperties()[0] ?? null;
if ($firstEnumProperty === null) {
throw new Exception('Enum must have at least one property');
}

$firstEnumPropValue = $firstEnumProperty->getValue();
if (is_int($firstEnumPropValue)) {
$type = 'int';
} elseif (is_string($firstEnumPropValue)) {
$type = 'string';
} else {
throw new Exception('Enum property must be int or string, got ' . gettype($firstEnumPropValue));
}
$props = self::convertEnumToGoEnumProperties($dto->getProperties(), $dto->getName());

return sprintf("type %s %s\n\nconst (%s\n)", $dto->getName(), $type, $props);
}

/**
* @param DtoEnumProperty[] $properties
* @throws Exception
*/
private function convertEnumToGoEnumProperties(array $properties, string $enum): string
{
$string = '';

$maxEnumPropNameLength = 0;
foreach ($properties as $prop) {
$maxEnumPropNameLength = max($maxEnumPropNameLength, strlen($prop->getName()));
}

foreach ($properties as $prop) {
$const = $prop->getName();
if (in_array($const, $this->usedConstantsStore)) {
$const .= $enum;
}
if (array_key_exists($const, $this->usedConstantsStore)) {
throw new Exception('Please rename constant ' . $const);
}
$this->usedConstantsStore[] = $const;

$spaces = str_repeat(' ', $maxEnumPropNameLength - strlen($prop->getName()) + 1);

$value = $prop->isNumeric() ? $prop->getValue() : sprintf('"%s"', $prop->getValue());
$string .= sprintf("\n\t%s$spaces%s = %s", $const, $enum, $value);
}

return $string;
}
}
72 changes: 72 additions & 0 deletions src/OutputGenerator/Go/GoOutputGenerator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

declare(strict_types=1);

namespace Riverwaysoft\PhpConverter\OutputGenerator\Go;

use Exception;
use Riverwaysoft\PhpConverter\Ast\ConverterResult;
use Riverwaysoft\PhpConverter\Dto\DtoList;
use Riverwaysoft\PhpConverter\Dto\DtoType;
use Riverwaysoft\PhpConverter\Dto\ExpressionType;
use Riverwaysoft\PhpConverter\OutputGenerator\OutputGeneratorInterface;
use Riverwaysoft\PhpConverter\OutputWriter\OutputFile;
use Riverwaysoft\PhpConverter\OutputWriter\OutputProcessor\OutputFilesProcessor;
use Riverwaysoft\PhpConverter\OutputWriter\OutputWriterInterface;

class GoOutputGenerator implements OutputGeneratorInterface
{
private OutputFilesProcessor $outputFilesProcessor;

private GoEnumResolver $enumResolver;

public function __construct(
private OutputWriterInterface $outputWriter,
private GoTypeResolver $resolver,
?OutputFilesProcessor $outputFilesProcessor = null,
) {
$this->outputFilesProcessor = OutputFilesProcessorProvider::provide($outputFilesProcessor);
$this->enumResolver = new GoEnumResolver();
}

/**
* @return OutputFile[]
* @throws Exception
*/
public function generate(ConverterResult $result): array
{
$this->outputWriter->reset();
foreach ($result->dtoList->getList() as $dto) {
$this->outputWriter->writeType($this->convert($dto, $result->dtoList), $dto);
}

return $this->outputFilesProcessor->process($this->outputWriter->getTypes());
}

/** @throws Exception */
private function convert(DtoType $dto, DtoList $dtoList): string
{
if ($dto->getExpressionType()->equals(ExpressionType::class())) {
$structProps = '';
$maxStructPropNameLength = 0;
foreach ($dto->getProperties() as $prop) {
$maxStructPropNameLength = max($maxStructPropNameLength, strlen($prop->getName()));
}
foreach ($dto->getProperties() as $prop) {
$spaces = str_repeat(' ', $maxStructPropNameLength - strlen($prop->getName()) + 1);

$structProps .= sprintf(
"\n\t%s$spaces%s",
ucfirst($prop->getName()),
$this->resolver->resolve($prop->getType(), $dto, $dtoList)
);
}

return sprintf("type %s struct {%s\n}", $dto->getName(), $structProps);
}
if ($dto->getExpressionType()->isAnyEnum()) {
return $this->enumResolver->resolve($dto);
}
throw new Exception('Unknown expression type ' . $dto->getExpressionType()->jsonSerialize());
}
}
56 changes: 56 additions & 0 deletions src/OutputGenerator/Go/GoRecursionValidator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

declare(strict_types=1);

namespace Riverwaysoft\PhpConverter\OutputGenerator\Go;

use Exception;
use Riverwaysoft\PhpConverter\Dto\DtoClassProperty;
use Riverwaysoft\PhpConverter\Dto\DtoList;
use Riverwaysoft\PhpConverter\Dto\DtoType;
use Riverwaysoft\PhpConverter\Dto\PhpType\PhpUnknownType;
use Riverwaysoft\PhpConverter\OutputGenerator\UnknownTypeResolver\ClassNameTypeResolver;

class GoRecursionValidator
{
/**
* @param string[] $visited
* @throws Exception
*/
public static function isRecursionFound(DtoType $dto, DtoList $dtoList, array $visited = []): bool
{
$classNameResolver = new ClassNameTypeResolver();

foreach ($dto->getProperties() as $value) {
if (!$value instanceof DtoClassProperty) {
continue;
}
$type = $value->getType();
if (!$type instanceof PhpUnknownType) {
continue;
}
if (!$classNameResolver->supports($type, $dto, $dtoList)) {
continue;
}

$dtoName = $dto->getName();
if (in_array($dtoName, $visited)) {
return true;
}

$visited[] = $dtoName;

/** @var string $resolvedType */
$resolvedType = $classNameResolver->resolve($type, $dto, $dtoList);

$resolvedDto = $dtoList->getDtoByType($resolvedType);
if (!$resolvedDto) {
throw new Exception(sprintf('Unknown type %s', $resolvedType));
}

return self::isRecursionFound($resolvedDto, $dtoList, $visited);
}

return false;
}
}
Loading

0 comments on commit a6d4c9b

Please sign in to comment.