luban/src/Luban.Job.Common/Source/Defs/DefFieldBase.cs

200 lines
7.3 KiB
C#

using Luban.Common.Utils;
using Luban.Job.Common.RawDefs;
using Luban.Job.Common.Types;
using Luban.Job.Common.Utils;
using System;
using System.Collections.Generic;
namespace Luban.Job.Common.Defs
{
public abstract class DefFieldBase
{
public DefAssemblyBase AssemblyBase => HostType.AssemblyBase;
public DefTypeBase HostType { get; set; }
public int Id { get; protected set; }
public string Name { get; protected set; }
public int AutoId { get; set; }
public string ConventionName
{
get
{
string cn;
ELanguage curLan = AssemblyBase.CurrentLanguage;
switch (AssemblyBase.NamingConventionBeanMember)
{
case NamingConvention.None: cn = Name; break;
case NamingConvention.CameraCase: cn = TypeUtil.ToCamelCase(Name); break;
case NamingConvention.PascalCase: cn = TypeUtil.ToPascalCase(Name); break;
case NamingConvention.UnderScores: cn = TypeUtil.ToUnderScores(Name); break;
case NamingConvention.Invalid: throw new Exception($"invalid NamingConvention");
case NamingConvention.LanguangeRecommend:
{
switch (curLan)
{
case ELanguage.INVALID: throw new Exception($"not set current language. can't get recommend naming convention name");
case ELanguage.CS: cn = TypeUtil.ToPascalCase(Name); break;
case ELanguage.JAVA: cn = TypeUtil.ToCamelCase(Name); break;
case ELanguage.GO: cn = TypeUtil.ToPascalCase(Name); break;
case ELanguage.CPP: cn = TypeUtil.ToCamelCase(Name); break;
case ELanguage.LUA: cn = TypeUtil.ToUnderScores(Name); break;
case ELanguage.JAVASCRIPT: cn = TypeUtil.ToCamelCase(Name); break;
case ELanguage.TYPESCRIPT: cn = TypeUtil.ToCamelCase(Name); break;
case ELanguage.PYTHON: cn = TypeUtil.ToUnderScores(Name); break;
case ELanguage.RUST: cn = TypeUtil.ToUnderScores(Name); break;
case ELanguage.PROTOBUF: cn = Name; break;
default: throw new Exception($"unknown language:{curLan}");
}
break;
}
default: throw new Exception($"unknown NamingConvention:{AssemblyBase.NamingConventionBeanMember}");
}
if (curLan == ELanguage.RUST)
{
if (cn == "type")
{
cn = "r#type";
}
}
return cn;
}
}
public string Type { get; }
public TType CType { get; protected set; }
public bool IsNullable => CType.IsNullable;
public string UpperCaseName => Name.ToUpper();
public string Comment { get; }
public string EscapeComment => DefUtil.EscapeCommentByCurrentLanguage(Comment);
public Dictionary<string, string> Tags { get; }
public bool IgnoreNameValidation { get; set; }
public bool HasTag(string attrName)
{
return Tags != null && Tags.ContainsKey(attrName);
}
public string GetTag(string attrName)
{
return Tags != null && Tags.TryGetValue(attrName, out var value) ? value : null;
}
public DefFieldBase(DefTypeBase host, Field f, int idOffset)
{
HostType = host;
Id = f.Id + idOffset;
AutoId = Id;
Name = f.Name;
Type = f.Type;
Comment = f.Comment;
Tags = DefUtil.ParseAttrs(f.Tags);
IgnoreNameValidation = f.IgnoreNameValidation;
}
public virtual void Compile()
{
if (Id < 0 || Id > 256)
{
throw new Exception($"type:'{HostType.FullName}' field:'{Name}' id:{Id} 超出范围");
}
if (!IgnoreNameValidation && !TypeUtil.IsValidName(Name))
{
throw new Exception($"type:'{HostType.FullName}' filed name:'{Name}' is reserved");
}
try
{
CType = AssemblyBase.CreateType(HostType.Namespace, Type);
}
catch (Exception e)
{
throw new Exception($"type:'{HostType.FullName}' filed:'{Name}' type:'{Type}' is invalid", e);
}
//if (IsNullable && (CType.IsCollection || (CType is TBean)))
//{
// throw new Exception($"type:{HostType.FullName} filed:{Name} type:{Type} is collection or bean. not support nullable");
//}
switch (CType)
{
case TArray t:
{
if (t.ElementType is TBean e && !e.IsDynamic && e.Bean.HierarchyFields.Count == 0)
{
throw new Exception($"container element type:'{e.Bean.FullName}' can't be empty bean");
}
break;
}
case TList t:
{
if (t.ElementType is TBean e && !e.IsDynamic && e.Bean.HierarchyFields.Count == 0)
{
throw new Exception($"container element type:'{e.Bean.FullName}' can't be empty bean");
}
break;
}
}
}
public virtual void PostCompile()
{
CType.Compile(this);
}
public static void CompileFields<T>(DefTypeBase hostType, List<T> fields, bool verifyId) where T : DefFieldBase
{
if (verifyId)
{
var ids = new HashSet<int>();
foreach (var f in fields)
{
if (f.Id == 0)
{
throw new Exception($"type:'{hostType.FullName}' field:'{f.Name}' id can't be 0");
}
if (!ids.Add(f.Id))
{
throw new Exception($"type:'{hostType.FullName}' field:'{f.Name}' id:{f.Id} duplicate");
}
}
}
var names = new HashSet<string>();
foreach (var f in fields)
{
var fname = f.Name;
if (fname.Length == 0)
{
throw new Exception($"type:'{hostType.FullName}' field id:{f.Id} name can't be empty");
}
if (!names.Add(fname))
{
throw new Exception($"type:'{hostType.FullName}' 'field:{fname}' duplicate");
}
if (TypeUtil.ToCsStyleName(fname) == hostType.Name)
{
throw new Exception($"type:'{hostType.FullName}' field:'{fname}' 生成的c#字段名与类型名相同,会引起编译错误");
}
}
foreach (var f in fields)
{
f.Compile();
}
}
}
}