Skip to content

Commit

Permalink
[new] 支持php-json
Browse files Browse the repository at this point in the history
  • Loading branch information
pirunxi committed Mar 24, 2024
1 parent 59e034c commit 3342173
Show file tree
Hide file tree
Showing 14 changed files with 484 additions and 22 deletions.
3 changes: 3 additions & 0 deletions src/Luban.Core/CodeTarget/CommonFileHeaders.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,8 @@ the code is regenerated.
# Changes to this file may cause incorrect behavior and will be lost if
# the code is regenerated.
# </auto-generated>
";

public const string AUTO_GENERATE_PHP = @"<?php
";
}
5 changes: 5 additions & 0 deletions src/Luban.PHP/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@


using Luban;

[assembly: RegisterBehaviour]
35 changes: 35 additions & 0 deletions src/Luban.PHP/CodeTarget/PHPCodeTargetBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using Luban.CodeFormat;
using Luban.CodeFormat.CodeStyles;
using Luban.CodeTarget;
using Luban.PHP.TemplateExtensions;
using Scriban;

namespace Luban.PHP.CodeTarget;

public abstract class PHPCodeTargetBase : AllInOneTemplateCodeTargetBase
{
public override string FileHeader => CommonFileHeaders.AUTO_GENERATE_PHP;

protected override string FileSuffixName => "php";

private readonly static ICodeStyle s_codeStyle = new ConfigurableCodeStyle("pascal", "pascal", "camel", "camel", "camel", "none");

protected override ICodeStyle DefaultCodeStyle => s_codeStyle;

protected override string DefaultOutputFileName => "schema.php";

private static readonly HashSet<string> s_preservedKeyWords = new()
{
// PHP preserved key words
"__halt_compiler","abstract","and","array","as","break","callable","case","catch","class","clone","const","continue","declare",
"default","die","do","echo","else","elseif","empty","enddeclare","endfor","endforeach","endif","endswitch","endwhile","eval",
"exit","extends","final","finally","for","foreach","function","global","goto","if","implements","include","include_once","instanceof","insteadof","interface"
};

protected override IReadOnlySet<string> PreservedKeyWords => s_preservedKeyWords;

protected override void OnCreateTemplateContext(TemplateContext ctx)
{
ctx.PushGlobal(new PHPCommonTemplateExtension());
}
}
15 changes: 15 additions & 0 deletions src/Luban.PHP/CodeTarget/PHPJsonCodeTarget.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Luban.CodeTarget;
using Luban.PHP.TemplateExtensions;
using Scriban;

namespace Luban.PHP.CodeTarget;

[CodeTarget("php-json")]
public class PHPJsonCodeTarget : PHPCodeTargetBase
{
protected override void OnCreateTemplateContext(TemplateContext ctx)
{
base.OnCreateTemplateContext(ctx);
ctx.PushGlobal(new PHPJsonTemplateExtension());
}
}
60 changes: 60 additions & 0 deletions src/Luban.PHP/Luban.PHP.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>disable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Luban.Core\Luban.Core.csproj" />
<ProjectReference Include="..\Luban.DataTarget.Builtin\Luban.DataTarget.Builtin.csproj" />
</ItemGroup>

<ItemGroup>
<None Update="Templates\cs-bin\bean.sbn">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Templates\cs-bin\table.sbn">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Templates\cs-bin\tables.sbn">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Templates\cs-dotnet-json\bean.sbn">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Templates\cs-dotnet-json\table.sbn">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Templates\cs-dotnet-json\tables.sbn">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Templates\common\cs\enum.sbn">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Templates\common\php\enum.sbn">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Templates\ts-json\bean.sbn">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Templates\ts-json\table.sbn">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Templates\ts-json\tables.sbn">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Templates\ts-json\schema.sbn">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Templates\php-json\schema.sbn">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>

<ItemGroup>
<Folder Include="TypeVisitors\" />
</ItemGroup>

</Project>
38 changes: 38 additions & 0 deletions src/Luban.PHP/TemplateExtensions/PHPCommonTemplateExtension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using Luban.CodeFormat;
using Luban.Defs;
using Luban.Types;
using Luban.Utils;
using Scriban.Runtime;

namespace Luban.PHP.TemplateExtensions;

public class PHPCommonTemplateExtension : ScriptObject
{
public static string FullName(DefTypeBase type)
{
return TypeUtil.MakePyFullName(type.Namespace, type.Name);
}

public static string ClassModifier(DefBean bean)
{
return bean.IsAbstractType ? "abstract" : "";
}

public static string NamespaceWithGraceBegin(string ns)
{
if (string.IsNullOrEmpty(ns))
{
return "";
}
return string.Join("", ns.Split('.').Select(n => $"namespace {n} {{"));
}

public static string NamespaceWithGraceEnd(string ns)
{
if (string.IsNullOrEmpty(ns))
{
return "";
}
return string.Join("", ns.Split('.').Select(n => $"}}"));
}
}
13 changes: 13 additions & 0 deletions src/Luban.PHP/TemplateExtensions/PHPJsonTemplateExtension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Luban.PHP.TypeVisitors;
using Luban.Types;
using Scriban.Runtime;

namespace Luban.PHP.TemplateExtensions;

public class PHPJsonTemplateExtension : ScriptObject
{
public static string Deserialize(string fieldName, string jsonVar, TType type)
{
return type.Apply(JsonDeserializeVisitor.Ins, jsonVar, fieldName, 0);
}
}
2 changes: 2 additions & 0 deletions src/Luban.PHP/Templates/common/php/enum.sbn
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@


155 changes: 155 additions & 0 deletions src/Luban.PHP/Templates/php-json/schema.sbn
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
{{~namespace_with_grace_begin __namespace~}}

{{~for enum in __enums~}}
{{~if enum.comment != '' ~}}
/**
* {{enum.comment | html.escape}}
*/
{{~end~}}
class {{full_name enum}} {
{{~for item in enum.items ~}}
{{~if item.comment != '' ~}}
/**
* {{escape_comment item.comment}}
*/
{{~end~}}
public const {{item.name}} = {{item.value}};
{{~end~}}
}

{{~end~}}


{{~for bean in __beans~}}
{{name = (full_name bean)}}
{{~if bean.comment != '' ~}}
/**
* {{escape_comment bean.comment}}
*/
{{~end~}}
{{class_modifier bean}} class {{name}}{{if bean.parent_def_type}} extends {{full_name bean.parent_def_type}}{{end}} {
{{~if bean.is_abstract_type~}}
public static function constructFrom($_json_) {
$type = $_json_['$type'];
switch ($type) {
{{~ for child in bean.hierarchy_not_abstract_children~}}
case '{{impl_data_type child bean}}': return new {{full_name child}}($_json_);
{{~end~}}
default: throw new \Exception("unknown type:$type");
}
}
{{~end~}}

public function __construct($_json_) {
{{~if bean.parent_def_type~}}
parent::__construct($_json_);
{{~end~}}
{{~ for field in bean.export_fields ~}}
{{~if !field.ctype.is_nullable~}}
if (!array_key_exists('{{field.name}}', $_json_)) { throw new \Exception("field:'{{field.name}}' missing"); }
{{~end~}}
{{deserialize ('$this->' + format_field_name __code_style field.name) ( '$_json_[\'' + field.name + '\']') field.ctype}};
{{~end~}}
}

{{~ for field in bean.export_fields ~}}
{{~if field.comment != '' ~}}
/**
* {{escape_comment field.comment}}
*/
{{~end~}}
public ${{format_field_name __code_style field.name}};
{{~end~}}
}


{{~end~}}

{{~for table in __tables
key_type = table.key_ttype
value_type = table.value_ttype
name = (full_name table)
~}}

{{~if table.comment != '' ~}}
/**
* {{escape_comment table.comment}}
*/
{{~end~}}
class {{name}} {
{{~if table.is_map_table ~}}
private $_dataMap;
private $_dataList;
public function __construct($_json_) {
$this->_dataMap = [];
$this->_dataList = [];
foreach ($_json_ as $_json2_) {
{{deserialize '$_v' '$_json2_' value_type}};
array_push($this->_dataList, $_v);
$this->_dataMap[$_v->{{format_field_name __code_style table.index_field.name}}] = $_v;
}
}

public function getDataMap() { return $this->_dataMap; }
public function getDataList() { return $this->_dataList; }

public function get($key) { return $this->_dataMap[$key]; }

{{~else if table.is_list_table ~}}
private $_dataList;

public function __construct($_json_) {
$this->_dataList = [];
foreach ($_json_ as $_json2_) {
{{deserialize '$_v' '$_json2_' value_type}};
array_push($this->_dataList, $_v);
}
}

public function getDataList() { return $this->_dataList; }

public function get($index) { return $this->_dataList[$index]; }

{{~else~}}

private $_data;
public function __construct($_json_) {
if (count($_json_) != 1) throw new \Exception('table:{{table.name}} mode=one, but size != 1');
{{deserialize '$this->_data' '$_json_[0]' value_type}};
}

public function getData() { return $this->_data; }

{{~ for field in value_type.def_bean.hierarchy_export_fields ~}}
{{~if field.comment != '' ~}}
/**
* {{escape_comment field.comment}}
*/
{{~end~}}
public function get{{format_field_name __code_style field.name}}() { return $this->_data->{{format_field_name __code_style field.name}}; }
{{~end~}}

{{end}}
}

{{~end~}}

class {{__name}} {
{{~ for table in __tables ~}}
private $_{{table.name}};
{{~if table.comment != '' ~}}
/**
* {{escape_comment table.comment}}
*/
{{~end~}}
public function get{{table.name}}() { return $this->_{{table.name}}; }
{{~end~}}

public function __construct($loader) {
{{~for table in __tables ~}}
$this->_{{table.name}} = new {{full_name table}}($loader('{{table.output_data_file}}'));
{{~end~}}
}
}

{{~namespace_with_grace_end __namespace~}}
26 changes: 26 additions & 0 deletions src/Luban.PHP/TypeVisitors/JsonDeserializeVisitor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using Luban.Types;
using Luban.TypeVisitors;

namespace Luban.PHP.TypeVisitors;

public class JsonDeserializeVisitor : DecoratorFuncVisitor<string, string, int, string>
{
public static JsonDeserializeVisitor Ins { get; } = new();

public override string DoAccept(TType type, string jsonFieldName, string fieldName, int depth)
{
if (type.IsNullable)
{
return $"if({jsonFieldName} != null) {{ {type.Apply(JsonUnderlyingDeserializeVisitor.Ins, jsonFieldName, fieldName, depth)}; }} else {{ {fieldName} = null; }}";
}
else
{
return type.Apply(JsonUnderlyingDeserializeVisitor.Ins, jsonFieldName, fieldName, depth);
}
}

//public override string Accept(TBean type, string bytebufName, string fieldName)
//{
// return type.Apply(TypescriptJsonUnderingConstructorVisitor.Ins, bytebufName, fieldName);
//}
}
Loading

0 comments on commit 3342173

Please sign in to comment.