From a78c9abd1a9789cdb093307e1aa41cbdd22a4bad Mon Sep 17 00:00:00 2001 From: walon Date: Sun, 5 Dec 2021 20:49:00 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E7=89=B9=E6=80=A7=E3=80=91=E6=96=B0?= =?UTF-8?q?=E5=A2=9Erefgroup=EF=BC=8C=E6=96=B9=E4=BE=BF=E5=BE=88=E5=A4=9A?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E9=83=BD=E5=BC=95=E7=94=A8=E5=88=B0=E5=90=8C?= =?UTF-8?q?=E4=B8=80=E7=BB=84=E5=BC=95=E7=94=A8=E8=A1=A8=E7=9A=84=E6=83=85?= =?UTF-8?q?=E5=86=B5=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Luban.Job.Cfg/Source/Defs/CfgDefLoader.cs | 19 +++ src/Luban.Job.Cfg/Source/Defs/DefAssembly.cs | 22 +++ src/Luban.Job.Cfg/Source/Defs/DefRefGroup.cs | 22 +++ src/Luban.Job.Cfg/Source/GenArgs.cs | 2 - src/Luban.Job.Cfg/Source/RawDefs/Defines.cs | 10 +- src/Luban.Job.Cfg/Source/RawDefs/RefGroup.cs | 15 ++ .../Source/Validators/RefValidator.cs | 148 +++++++++++------- .../Source/Defs/DefFieldBase.cs | 2 +- src/Luban.Job.Common/Source/Types/TArray.cs | 4 +- src/Luban.Job.Common/Source/Types/TList.cs | 4 +- src/Luban.Job.Common/Source/Types/TMap.cs | 4 +- src/Luban.Job.Common/Source/Types/TSet.cs | 4 +- src/Luban.Job.Common/Source/Types/TType.cs | 2 +- .../Source/Utils/RenderFileUtil.cs | 4 +- 14 files changed, 184 insertions(+), 78 deletions(-) create mode 100644 src/Luban.Job.Cfg/Source/Defs/DefRefGroup.cs create mode 100644 src/Luban.Job.Cfg/Source/RawDefs/RefGroup.cs diff --git a/src/Luban.Job.Cfg/Source/Defs/CfgDefLoader.cs b/src/Luban.Job.Cfg/Source/Defs/CfgDefLoader.cs index 80d06b4..dadcb86 100644 --- a/src/Luban.Job.Cfg/Source/Defs/CfgDefLoader.cs +++ b/src/Luban.Job.Cfg/Source/Defs/CfgDefLoader.cs @@ -38,6 +38,8 @@ namespace Luban.Job.Cfg.Defs private readonly List _defaultGroups = new List(); + private readonly List _refGroups = new(); + public CfgDefLoader(IAgent agent) : base(agent) { RegisterRootDefineHandler("importexcel", AddImportExcel); @@ -46,6 +48,7 @@ namespace Luban.Job.Cfg.Defs RegisterRootDefineHandler("group", AddGroup); RegisterModuleDefineHandler("table", AddTable); + RegisterModuleDefineHandler("refgroup", AddRefGroup); IsBeanFieldMustDefineId = false; @@ -59,6 +62,7 @@ namespace Luban.Job.Cfg.Defs Tables = _cfgTables, Services = _cfgServices, Groups = _cfgGroups, + RefGroups = _refGroups, }; BuildCommonDefines(defines); return defines; @@ -835,5 +839,20 @@ namespace Luban.Job.Cfg.Defs AddBean(defineFile, cb, fullname); } } + + + private static readonly List _refGroupRequireAttrs = new List { "name", "ref" }; + + private void AddRefGroup(string defineFile, XElement e) + { + ValidAttrKeys(defineFile, e, null, _refGroupRequireAttrs); + + var refGroup = new RefGroup() + { + Name = XmlUtil.GetRequiredAttribute(e, "name"), + Refs = XmlUtil.GetRequiredAttribute(e, "ref").Split(",").Select(s => s.Trim()).ToList(), + }; + _refGroups.Add(refGroup); + } } } diff --git a/src/Luban.Job.Cfg/Source/Defs/DefAssembly.cs b/src/Luban.Job.Cfg/Source/Defs/DefAssembly.cs index 8b24fd2..b21bd21 100644 --- a/src/Luban.Job.Cfg/Source/Defs/DefAssembly.cs +++ b/src/Luban.Job.Cfg/Source/Defs/DefAssembly.cs @@ -57,6 +57,8 @@ namespace Luban.Job.Cfg.Defs private readonly List _cfgServices = new List(); + private readonly Dictionary _refGroups = new(); + private readonly ConcurrentDictionary _recordsByTables = new(); public Dictionary CfgTablesByName = new(); @@ -199,6 +201,20 @@ namespace Luban.Job.Cfg.Defs return refTypes.Values.ToList(); } + private void AddRefGroup(RefGroup g) + { + if (_refGroups.ContainsKey(g.Name)) + { + throw new Exception($"refgroup:{g.Name} 重复"); + } + _refGroups.Add(g.Name, new DefRefGroup(g)); + } + + public DefRefGroup GetRefGroup(string groupName) + { + return _refGroups.TryGetValue(groupName, out var refGroup) ? refGroup : null; + } + public void Load(Defines defines, RemoteAgent agent, GenArgs args) { LoadCommon(defines, agent, args); @@ -225,6 +241,11 @@ namespace Luban.Job.Cfg.Defs this._patches.AddRange(defines.Patches); + foreach (var g in defines.RefGroups) + { + AddRefGroup(g); + } + foreach (var e in defines.Enums) { AddType(new DefEnum(e)); @@ -278,6 +299,7 @@ namespace Luban.Job.Cfg.Defs throw; } } + foreach (var type in Types.Values) { try diff --git a/src/Luban.Job.Cfg/Source/Defs/DefRefGroup.cs b/src/Luban.Job.Cfg/Source/Defs/DefRefGroup.cs new file mode 100644 index 0000000..e7352da --- /dev/null +++ b/src/Luban.Job.Cfg/Source/Defs/DefRefGroup.cs @@ -0,0 +1,22 @@ +using Luban.Job.Cfg.RawDefs; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Luban.Job.Cfg.Defs +{ + public class DefRefGroup + { + public string Name { get; } + + public List Refs { get; } + + public DefRefGroup(RefGroup group) + { + this.Name = group.Name; + this.Refs = group.Refs; + } + } +} diff --git a/src/Luban.Job.Cfg/Source/GenArgs.cs b/src/Luban.Job.Cfg/Source/GenArgs.cs index 99c5a97..f18cd84 100644 --- a/src/Luban.Job.Cfg/Source/GenArgs.cs +++ b/src/Luban.Job.Cfg/Source/GenArgs.cs @@ -38,8 +38,6 @@ namespace Luban.Job.Cfg [Option("output:exclude_tags", Required = false, HelpText = "export exclude tags. default export all tags")] public string OutputExcludeTags { get; set; } = ""; - - [Option("template:data:file", Required = false, HelpText = "template name. use with gen_types=data_template")] public string TemplateDataFile { get; set; } diff --git a/src/Luban.Job.Cfg/Source/RawDefs/Defines.cs b/src/Luban.Job.Cfg/Source/RawDefs/Defines.cs index 9c6d04a..69d1c17 100644 --- a/src/Luban.Job.Cfg/Source/RawDefs/Defines.cs +++ b/src/Luban.Job.Cfg/Source/RawDefs/Defines.cs @@ -5,12 +5,14 @@ namespace Luban.Job.Cfg.RawDefs { public class Defines : DefinesCommon { - public List Patches { get; set; } = new List(); + public List Patches { get; set; } = new(); - public List Tables { get; set; } = new List
(); + public List
Tables { get; set; } = new(); - public List Groups { get; set; } = new List(); + public List Groups { get; set; } = new(); - public List Services { get; set; } = new List(); + public List Services { get; set; } = new(); + + public List RefGroups { get; set; } = new(); } } diff --git a/src/Luban.Job.Cfg/Source/RawDefs/RefGroup.cs b/src/Luban.Job.Cfg/Source/RawDefs/RefGroup.cs new file mode 100644 index 0000000..9ecda90 --- /dev/null +++ b/src/Luban.Job.Cfg/Source/RawDefs/RefGroup.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Luban.Job.Cfg.RawDefs +{ + public class RefGroup + { + public string Name { get; set; } + + public List Refs { get; set; } + } +} diff --git a/src/Luban.Job.Cfg/Source/Validators/RefValidator.cs b/src/Luban.Job.Cfg/Source/Validators/RefValidator.cs index d2e41de..41b6441 100644 --- a/src/Luban.Job.Cfg/Source/Validators/RefValidator.cs +++ b/src/Luban.Job.Cfg/Source/Validators/RefValidator.cs @@ -24,6 +24,8 @@ namespace Luban.Job.Cfg.Validators public bool GenRef { get; private set; } + private readonly List<(DefTable Table, string Index, bool IgnoreDefault)> _compiledTables = new(); + public RefValidator(TType type, string tablesStr) { Type = type; @@ -40,24 +42,23 @@ namespace Luban.Job.Cfg.Validators var assembly = ctx.Assembly; #if !LUBAN_LITE - foreach (var table in Tables) + foreach (var tableInfo in _compiledTables) { - var (actualTable, field, zeroAble) = ParseRefString(table); + var (defTable, field, zeroAble) = tableInfo; if (zeroAble && key.Apply(IsDefaultValue.Ins)) { return; } - DefTable ct = assembly.GetCfgTable(actualTable); - switch (ct.Mode) + switch (defTable.Mode) { case ETableMode.ONE: { - throw new NotSupportedException($"{actualTable} 是singleton表,不支持ref"); + throw new NotSupportedException($"{defTable.FullName} 是singleton表,不支持ref"); } case ETableMode.MAP: { - var recordMap = assembly.GetTableDataInfo(ct).FinalRecordMap; + var recordMap = assembly.GetTableDataInfo(defTable).FinalRecordMap; if (recordMap.ContainsKey(key)) { return; @@ -66,7 +67,7 @@ namespace Luban.Job.Cfg.Validators } case ETableMode.LIST: { - var recordMap = assembly.GetTableDataInfo(ct).FinalRecordMapByIndexs[field]; + var recordMap = assembly.GetTableDataInfo(defTable).FinalRecordMapByIndexs[field]; if (recordMap.ContainsKey(key)) { return; @@ -78,11 +79,9 @@ namespace Luban.Job.Cfg.Validators } string source = ValidatorContext.CurrentVisitor.CurrentValidateRecord.Source; - foreach (var table in Tables) + foreach (var table in _compiledTables) { - var (actualTable, field, zeroAble) = ParseRefString(table); - DefTable ct = assembly.GetCfgTable(actualTable); - assembly.Agent.Error("记录 {0} = {1} (来自文件:{2}) 在引用表:{3} 中不存在", ValidatorContext.CurrentRecordPath, key, source, table); + assembly.Agent.Error("记录 {0} = {1} (来自文件:{2}) 在引用表:{3} 中不存在", ValidatorContext.CurrentRecordPath, key, source, table.Table.FullName); } #endif } @@ -126,80 +125,109 @@ namespace Luban.Job.Cfg.Validators string fieldName = def.Name; if (Tables.Count == 0) { - throw new Exception($"结构:{ hostTypeName } 字段: { fieldName} ref 不能为空"); + throw new Exception($"结构:'{hostTypeName}' 字段: '{fieldName}' ref 不能为空"); } var assembly = ((DefField)def).Assembly; - bool first = true; foreach (var table in Tables) { var (actualTable, indexName, ignoreDefault) = ParseRefString(table); - var ct = assembly.GetCfgTable(actualTable); - if (ct == null) + DefTable ct; + DefRefGroup refGroup; + if ((ct = assembly.GetCfgTable(actualTable)) != null) { - throw new Exception($"结构:{hostTypeName} 字段:{fieldName} ref:{actualTable} 不存在"); + CompileTable(def, ct, indexName, ignoreDefault); } - //if (!ct.NeedExport) - //{ - // throw new Exception($"type:'{hostTypeName}' field:'{fieldName}' ref 引用的表:'{actualTable}' 没有导出"); - //} - if (ct.IsOneValueTable) + else if ((refGroup = assembly.GetRefGroup(actualTable)) != null) { - if (string.IsNullOrEmpty(fieldName)) + if (!string.IsNullOrWhiteSpace(indexName)) { - throw new Exception($"结构:{hostTypeName} 字段:{fieldName} ref:{actualTable} 是singleton表,索引字段不能为空"); + throw new Exception($"refgroup:'{actualTable}' index:'{indexName}' 必须为空"); } - else + foreach (var rawRefTableName in refGroup.Refs) { - if (!ct.ValueTType.Bean.TryGetField(fieldName, out var indexField, out _)) + var (actualRefTableName, refIndex, refIgnoreDefault) = ParseRefString(rawRefTableName); + DefTable subTable = assembly.GetCfgTable(actualRefTableName); + if (subTable == null) { - throw new Exception($"结构:{hostTypeName} 字段:{fieldName} ref:{actualTable} value_type:{ct.ValueTType.Bean.FullName} 未包含索引字段:{fieldName}"); + throw new Exception($"结构:'{hostTypeName}' 字段:'{fieldName}' refgroup:'{actualTable}' ref:'{actualRefTableName}' 不存在"); } - if (!(indexField.CType is TMap tmap)) - { - throw new Exception($"结构:{hostTypeName} 字段:{fieldName} ref:{actualTable} value_type:{ct.ValueTType.Bean.FullName} 索引字段:{fieldName} type:{indexField.CType.TypeName} 不是map类型"); - } - if (tmap.KeyType.TypeName != Type.TypeName) - { - throw new Exception($"结构:{hostTypeName} 字段:{fieldName} 类型:'{Type.TypeName}' 与被引用的表:{actualTable} value_type:{ct.ValueTType.Bean.FullName} 索引字段:{fieldName} key_type:{tmap.KeyType.TypeName} 不一致"); - } - } - } - else if (ct.IsMapTable) - { - if (first && Tables.Count == 1 && ct.NeedExport) - { - // 只引用一个表时才生成ref代码。 - // 如果被引用的表没有导出,生成ref没有意义,还会产生编译错误 - GenRef = true; - } - if (!string.IsNullOrEmpty(indexName)) - { - throw new Exception($"结构:{hostTypeName} 字段:{fieldName} ref:{actualTable} 是map表,不能索引子字段"); - } - var keyType = ct.KeyTType; - if (keyType.TypeName != Type.TypeName) - { - throw new Exception($"type:'{hostTypeName}' field:'{fieldName}' 类型:'{Type.TypeName}' 与 被引用的map表:'{actualTable}' key类型:'{keyType.TypeName}' 不一致"); + CompileTable(def, subTable, refIndex, ignoreDefault && refIgnoreDefault); } } else { - if (string.IsNullOrEmpty(indexName)) + throw new Exception($"结构:'{hostTypeName}' 字段:'{fieldName}' ref:'{actualTable}' 不存在"); + } + } + if (_compiledTables.Count == 1 && (_compiledTables[0].Table is DefTable t && t.IsMapTable && t.NeedExport)) + { + // 只引用一个表时才生成ref代码。 + // 如果被引用的表没有导出,生成ref没有意义,还会产生编译错误 + GenRef = true; + } + } + + private void CompileTable(DefFieldBase def, DefTable ct, string indexName, bool ignoreDefault) + { + _compiledTables.Add((ct, indexName, ignoreDefault)); + + string actualTable = ct.FullName; + string hostTypeName = def.HostType.FullName; + string fieldName = def.Name; + //if (!ct.NeedExport) + //{ + // throw new Exception($"type:'{hostTypeName}' field:'{fieldName}' ref 引用的表:'{actualTable}' 没有导出"); + //} + if (ct.IsOneValueTable) + { + if (string.IsNullOrEmpty(fieldName)) + { + throw new Exception($"结构:{hostTypeName} 字段:{fieldName} ref:{actualTable} 是singleton表,索引字段不能为空"); + } + else + { + if (!ct.ValueTType.Bean.TryGetField(fieldName, out var indexField, out _)) { - throw new Exception($"结构:{hostTypeName} 字段:{fieldName} ref:{actualTable} 是list表,必须显式指定索引字段"); + throw new Exception($"结构:{hostTypeName} 字段:{fieldName} ref:{actualTable} value_type:{ct.ValueTType.Bean.FullName} 未包含索引字段:{fieldName}"); } - var indexField = ct.IndexList.Find(k => k.IndexField.Name == indexName); - if (indexField.Type == null) + if (!(indexField.CType is TMap tmap)) { - throw new Exception($"结构:{hostTypeName} 字段:{fieldName} 索引字段:{indexName} 不是被引用的list表:{actualTable} 的索引字段,合法值为'{ct.Index}'之一"); + throw new Exception($"结构:{hostTypeName} 字段:{fieldName} ref:{actualTable} value_type:{ct.ValueTType.Bean.FullName} 索引字段:{fieldName} type:{indexField.CType.TypeName} 不是map类型"); } - if (indexField.Type.TypeName != Type.TypeName) + if (tmap.KeyType.TypeName != Type.TypeName) { - throw new Exception($"type:'{hostTypeName}' field:'{fieldName}' 类型:'{Type.TypeName}' 与 被引用的list表:'{actualTable}' key:{indexName} 类型:'{indexField.Type.TypeName}' 不一致"); + throw new Exception($"结构:{hostTypeName} 字段:{fieldName} 类型:'{Type.TypeName}' 与被引用的表:{actualTable} value_type:{ct.ValueTType.Bean.FullName} 索引字段:{fieldName} key_type:{tmap.KeyType.TypeName} 不一致"); } } - first = false; + } + else if (ct.IsMapTable) + { + if (!string.IsNullOrEmpty(indexName)) + { + throw new Exception($"结构:{hostTypeName} 字段:{fieldName} ref:{actualTable} 是map表,不能索引子字段"); + } + var keyType = ct.KeyTType; + if (keyType.TypeName != Type.TypeName) + { + throw new Exception($"type:'{hostTypeName}' field:'{fieldName}' 类型:'{Type.TypeName}' 与 被引用的map表:'{actualTable}' key类型:'{keyType.TypeName}' 不一致"); + } + } + else + { + if (string.IsNullOrEmpty(indexName)) + { + throw new Exception($"结构:{hostTypeName} 字段:{fieldName} ref:{actualTable} 是list表,必须显式指定索引字段"); + } + var indexField = ct.IndexList.Find(k => k.IndexField.Name == indexName); + if (indexField.Type == null) + { + throw new Exception($"结构:{hostTypeName} 字段:{fieldName} 索引字段:{indexName} 不是被引用的list表:{actualTable} 的索引字段,合法值为'{ct.Index}'之一"); + } + if (indexField.Type.TypeName != Type.TypeName) + { + throw new Exception($"type:'{hostTypeName}' field:'{fieldName}' 类型:'{Type.TypeName}' 与 被引用的list表:'{actualTable}' key:{indexName} 类型:'{indexField.Type.TypeName}' 不一致"); + } } } } diff --git a/src/Luban.Job.Common/Source/Defs/DefFieldBase.cs b/src/Luban.Job.Common/Source/Defs/DefFieldBase.cs index 11263fd..3b19842 100644 --- a/src/Luban.Job.Common/Source/Defs/DefFieldBase.cs +++ b/src/Luban.Job.Common/Source/Defs/DefFieldBase.cs @@ -151,7 +151,7 @@ namespace Luban.Job.Common.Defs public virtual void PostCompile() { - CType.Compile(this); + CType.PostCompile(this); } public static void CompileFields(DefTypeBase hostType, List fields, bool verifyId) where T : DefFieldBase diff --git a/src/Luban.Job.Common/Source/Types/TArray.cs b/src/Luban.Job.Common/Source/Types/TArray.cs index df8fae0..4068905 100644 --- a/src/Luban.Job.Common/Source/Types/TArray.cs +++ b/src/Luban.Job.Common/Source/Types/TArray.cs @@ -28,9 +28,9 @@ namespace Luban.Job.Common.Types public override bool IsCollection => true; - public override void Compile(DefFieldBase field) + public override void PostCompile(DefFieldBase field) { - base.Compile(field); + base.PostCompile(field); foreach (var p in ElementType.Processors) { diff --git a/src/Luban.Job.Common/Source/Types/TList.cs b/src/Luban.Job.Common/Source/Types/TList.cs index fffeedc..bfce885 100644 --- a/src/Luban.Job.Common/Source/Types/TList.cs +++ b/src/Luban.Job.Common/Source/Types/TList.cs @@ -31,9 +31,9 @@ namespace Luban.Job.Common.Types public override bool IsCollection => true; - public override void Compile(DefFieldBase field) + public override void PostCompile(DefFieldBase field) { - base.Compile(field); + base.PostCompile(field); foreach (var p in ElementType.Processors) { diff --git a/src/Luban.Job.Common/Source/Types/TMap.cs b/src/Luban.Job.Common/Source/Types/TMap.cs index d734596..189647c 100644 --- a/src/Luban.Job.Common/Source/Types/TMap.cs +++ b/src/Luban.Job.Common/Source/Types/TMap.cs @@ -36,9 +36,9 @@ namespace Luban.Job.Common.Types public override bool IsCollection => true; - public override void Compile(DefFieldBase field) + public override void PostCompile(DefFieldBase field) { - base.Compile(field); + base.PostCompile(field); foreach (var p in KeyType.Processors) { diff --git a/src/Luban.Job.Common/Source/Types/TSet.cs b/src/Luban.Job.Common/Source/Types/TSet.cs index 78f1604..180c172 100644 --- a/src/Luban.Job.Common/Source/Types/TSet.cs +++ b/src/Luban.Job.Common/Source/Types/TSet.cs @@ -31,9 +31,9 @@ namespace Luban.Job.Common.Types public override bool IsCollection => true; - public override void Compile(DefFieldBase field) + public override void PostCompile(DefFieldBase field) { - base.Compile(field); + base.PostCompile(field); foreach (var p in ElementType.Processors) { diff --git a/src/Luban.Job.Common/Source/Types/TType.cs b/src/Luban.Job.Common/Source/Types/TType.cs index 3fb0c38..b05313e 100644 --- a/src/Luban.Job.Common/Source/Types/TType.cs +++ b/src/Luban.Job.Common/Source/Types/TType.cs @@ -37,7 +37,7 @@ namespace Luban.Job.Common.Types public abstract bool TryParseFrom(string s); - public virtual void Compile(DefFieldBase field) + public virtual void PostCompile(DefFieldBase field) { foreach (var p in Processors) { diff --git a/src/Luban.Job.Common/Source/Utils/RenderFileUtil.cs b/src/Luban.Job.Common/Source/Utils/RenderFileUtil.cs index 3c54ab6..987eb4f 100644 --- a/src/Luban.Job.Common/Source/Utils/RenderFileUtil.cs +++ b/src/Luban.Job.Common/Source/Utils/RenderFileUtil.cs @@ -110,14 +110,14 @@ namespace Luban.Job.Common.Utils { { "json", "json" }, { "lua", "lua" }, - { "bin", "bin" }, + { "bin", "bytes" }, { "xml", "xml" }, { "yaml", "yml" }, { "yml", "yml" }, { "erlang", "erl" }, { "erl", "erl" }, { "xlsx", "xlsx" }, - { "protobuf", "pb" }, + { "protobuf", "bytes" }, }; public static string GetOutputFileSuffix(string genType)