2021-01-11 09:41:43 -08:00
|
|
|
using System;
|
2021-01-13 05:09:09 -08:00
|
|
|
using System.Diagnostics;
|
|
|
|
using System.Reflection;
|
2021-01-15 14:28:21 -08:00
|
|
|
using System.Collections;
|
2021-01-11 09:41:43 -08:00
|
|
|
|
|
|
|
namespace Tests
|
|
|
|
{
|
|
|
|
class Comptime
|
|
|
|
{
|
|
|
|
[AttributeUsage(.All)]
|
|
|
|
struct IFaceAAttribute : Attribute, IComptimeTypeApply
|
|
|
|
{
|
|
|
|
String mMemberName;
|
|
|
|
int32 mInitVal;
|
|
|
|
|
|
|
|
public int32 InitVal
|
|
|
|
{
|
|
|
|
set mut
|
|
|
|
{
|
|
|
|
mInitVal = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public this(String memberName)
|
|
|
|
{
|
|
|
|
mMemberName = memberName;
|
|
|
|
mInitVal = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
[Comptime]
|
|
|
|
public void ApplyToType(Type type)
|
|
|
|
{
|
2021-01-13 05:09:09 -08:00
|
|
|
Compiler.EmitTypeBody(type, scope $"""
|
2021-01-11 09:41:43 -08:00
|
|
|
public int32 m{mMemberName} = {mInitVal};
|
|
|
|
public int32 GetVal{mMemberName}() => mC;
|
|
|
|
""");
|
2021-01-13 05:09:09 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[AttributeUsage(.Method)]
|
|
|
|
struct LogAttribute : Attribute, IComptimeMethodApply
|
|
|
|
{
|
|
|
|
public static String gLog = new .() ~ delete _;
|
2021-01-11 09:41:43 -08:00
|
|
|
|
2021-01-13 05:09:09 -08:00
|
|
|
[Comptime]
|
|
|
|
public void ApplyToMethod(ComptimeMethodInfo method)
|
|
|
|
{
|
|
|
|
String emit = scope $"LogAttribute.gLog.AppendF($\"Called {method}";
|
|
|
|
for (var fieldIdx < method.ParamCount)
|
|
|
|
emit.AppendF($" {{ {method.GetParamName(fieldIdx)} }}");
|
2021-01-16 12:35:51 -08:00
|
|
|
emit.Append("\\n\");");
|
2021-01-13 05:09:09 -08:00
|
|
|
Compiler.EmitMethodEntry(method, emit);
|
2021-01-16 12:35:51 -08:00
|
|
|
|
|
|
|
if (var genericType = method.ReturnType as SpecializedGenericType)
|
|
|
|
{
|
|
|
|
if ((genericType.UnspecializedType == typeof(Result<>)) || (genericType.UnspecializedType == typeof(Result<,>)))
|
|
|
|
{
|
|
|
|
Compiler.EmitMethodExit(method, """
|
|
|
|
if (@return case .Err)
|
|
|
|
LogAttribute.gLog.AppendF($"Error: {@return}");
|
|
|
|
""");
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2021-01-11 09:41:43 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[IFaceA("C", InitVal=345)]
|
|
|
|
class ClassA
|
|
|
|
{
|
|
|
|
public int mA = 123;
|
|
|
|
|
|
|
|
[OnCompile(.TypeInit), Comptime]
|
|
|
|
public static void Generate()
|
|
|
|
{
|
2021-01-13 05:09:09 -08:00
|
|
|
Compiler.EmitTypeBody(typeof(Self), """
|
2021-01-11 09:41:43 -08:00
|
|
|
public int32 mB = 234;
|
|
|
|
public int32 GetValB() => mB;
|
|
|
|
""");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-25 10:14:22 -08:00
|
|
|
[IFaceA("C", InitVal=345)]
|
|
|
|
struct StructA
|
|
|
|
{
|
|
|
|
public int mA = 123;
|
2021-11-26 08:59:46 -08:00
|
|
|
public static StructA sSA;
|
|
|
|
public const StructA cSA = .();
|
2021-02-25 10:14:22 -08:00
|
|
|
|
|
|
|
[OnCompile(.TypeInit), Comptime]
|
|
|
|
public static void Generate()
|
|
|
|
{
|
|
|
|
Compiler.EmitTypeBody(typeof(Self), """
|
|
|
|
public int32 mB = 234;
|
|
|
|
public int32 GetValB() => mB;
|
|
|
|
""");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-16 12:35:51 -08:00
|
|
|
enum MethodAErr
|
2021-01-13 05:09:09 -08:00
|
|
|
{
|
2021-01-16 12:35:51 -08:00
|
|
|
ErrorA,
|
|
|
|
ErrorB
|
|
|
|
}
|
2021-01-13 05:09:09 -08:00
|
|
|
|
2021-01-16 12:35:51 -08:00
|
|
|
[Log]
|
|
|
|
static Result<int, MethodAErr> MethodA(int a, int b)
|
|
|
|
{
|
|
|
|
return .Err(.ErrorB);
|
2021-01-13 05:09:09 -08:00
|
|
|
}
|
|
|
|
|
2021-01-16 06:26:55 -08:00
|
|
|
static Type GetBiggerType(Type t)
|
2021-01-15 14:28:21 -08:00
|
|
|
{
|
2021-01-16 06:26:55 -08:00
|
|
|
switch (t)
|
2021-01-15 14:28:21 -08:00
|
|
|
{
|
2021-01-16 06:26:55 -08:00
|
|
|
case typeof(int8): return typeof(int16);
|
|
|
|
case typeof(int16): return typeof(int32);
|
|
|
|
case typeof(int32): return typeof(int64);
|
|
|
|
case typeof(float): return typeof(double);
|
2021-01-15 14:28:21 -08:00
|
|
|
}
|
2021-01-16 06:26:55 -08:00
|
|
|
return null;
|
2021-01-15 14:28:21 -08:00
|
|
|
}
|
|
|
|
|
2021-01-16 06:26:55 -08:00
|
|
|
static TTo GetBigger<TFrom, TTo>(TFrom val) where TTo : comptype(GetBiggerType(typeof(TFrom))), operator explicit TFrom
|
2021-01-15 14:28:21 -08:00
|
|
|
{
|
2021-01-16 06:26:55 -08:00
|
|
|
return (.)val;
|
2021-01-15 14:28:21 -08:00
|
|
|
}
|
|
|
|
|
2021-01-19 05:40:57 -08:00
|
|
|
public struct TypePrinter<T>
|
|
|
|
{
|
|
|
|
const int cFieldCount = GetFieldCount();
|
|
|
|
const (int32, StringView)[cFieldCount] cMembers = Make();
|
|
|
|
|
|
|
|
static int GetFieldCount()
|
|
|
|
{
|
|
|
|
int fieldCount = 0;
|
|
|
|
for (let field in typeof(T).GetFields())
|
|
|
|
if (!field.IsStatic)
|
|
|
|
fieldCount++;
|
|
|
|
return fieldCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
static decltype(cMembers) Make()
|
|
|
|
{
|
|
|
|
if (cFieldCount == 0)
|
|
|
|
return default(decltype(cMembers));
|
|
|
|
|
|
|
|
decltype(cMembers) fields = ?;
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
for (let field in typeof(T).GetFields())
|
|
|
|
{
|
|
|
|
if (!field.IsStatic)
|
|
|
|
fields[i++] = (field.MemberOffset, field.Name);
|
|
|
|
}
|
|
|
|
|
|
|
|
return fields;
|
|
|
|
}
|
|
|
|
|
|
|
|
public override void ToString(String strBuffer)
|
|
|
|
{
|
|
|
|
for (var t in cMembers)
|
|
|
|
{
|
|
|
|
if (@t != 0)
|
|
|
|
strBuffer.Append("\n");
|
|
|
|
strBuffer.AppendF($"{t.0} {t.1}");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct TestType
|
|
|
|
{
|
|
|
|
public float mX;
|
|
|
|
public float mY;
|
|
|
|
public float mZ;
|
|
|
|
}
|
2021-12-16 07:28:03 -05:00
|
|
|
|
|
|
|
class SerializationContext
|
|
|
|
{
|
|
|
|
public String mStr = new String() ~ delete _;
|
|
|
|
public void Serialize<T>(String name, T val) where T : struct
|
|
|
|
{
|
|
|
|
mStr.AppendF($"{name} {val}\n");
|
|
|
|
}
|
|
|
|
}
|
2021-01-19 05:40:57 -08:00
|
|
|
|
2021-12-16 07:28:03 -05:00
|
|
|
interface ISerializable
|
|
|
|
{
|
|
|
|
void Serialize(SerializationContext ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
[AttributeUsage(.Enum | .Struct | .Class, .NotInherited | .ReflectAttribute | .DisallowAllowMultiple)]
|
|
|
|
struct SerializableAttribute : Attribute, IComptimeTypeApply
|
|
|
|
{
|
|
|
|
[Comptime]
|
|
|
|
public void ApplyToType(Type type)
|
|
|
|
{
|
|
|
|
const String SERIALIZE_NAME = "void ISerializable.Serialize(SerializationContext ctx)\n";
|
|
|
|
|
|
|
|
String serializeBuffer = new .();
|
|
|
|
|
|
|
|
Compiler.Assert(!type.IsUnion);
|
|
|
|
|
|
|
|
for (let field in type.GetFields())
|
|
|
|
{
|
|
|
|
if (!field.IsInstanceField || field.DeclaringType != type)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
serializeBuffer.AppendF($"\n\tctx.Serialize(\"{field.Name}\", {field.Name});");
|
|
|
|
}
|
|
|
|
|
|
|
|
Compiler.EmitTypeBody(type, scope $"{SERIALIZE_NAME}{{{serializeBuffer}\n}}\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[Serializable]
|
|
|
|
struct Foo : this(float x, float y), ISerializable
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
public class ComponentHandler<T>
|
|
|
|
where T : struct
|
|
|
|
{
|
|
|
|
uint8* data;
|
|
|
|
protected override void GCMarkMembers()
|
|
|
|
{
|
|
|
|
T* ptr = (T*)data;
|
|
|
|
GC.Mark!((*ptr));
|
|
|
|
}
|
|
|
|
}
|
2021-01-11 09:41:43 -08:00
|
|
|
[Test]
|
|
|
|
public static void TestBasics()
|
|
|
|
{
|
|
|
|
ClassA ca = scope .();
|
|
|
|
Test.Assert(ca.mA == 123);
|
|
|
|
Test.Assert(ca.mB == 234);
|
|
|
|
Test.Assert(ca.GetValB() == 234);
|
|
|
|
Test.Assert(ca.mC == 345);
|
|
|
|
Test.Assert(ca.GetValC() == 345);
|
2021-01-13 05:09:09 -08:00
|
|
|
|
2021-02-25 10:14:22 -08:00
|
|
|
StructA sa = .();
|
|
|
|
Test.Assert(sa.mA == 123);
|
|
|
|
Test.Assert(sa.mB == 234);
|
|
|
|
Test.Assert(sa.GetValB() == 234);
|
|
|
|
Test.Assert(sa.mC == 345);
|
|
|
|
Test.Assert(sa.GetValC() == 345);
|
|
|
|
|
2021-01-13 05:09:09 -08:00
|
|
|
Compiler.Mixin("int val = 99;");
|
|
|
|
Test.Assert(val == 99);
|
|
|
|
|
2021-01-16 12:35:51 -08:00
|
|
|
MethodA(34, 45).IgnoreError();
|
|
|
|
Debug.Assert(LogAttribute.gLog == "Called Tests.Comptime.MethodA(int a, int b) 34 45\nError: Err(ErrorB)");
|
2021-01-15 14:28:21 -08:00
|
|
|
|
2021-01-16 06:26:55 -08:00
|
|
|
var v0 = GetBigger((int8)123);
|
|
|
|
Test.Assert(v0.GetType() == typeof(int16));
|
2021-01-19 05:40:57 -08:00
|
|
|
|
|
|
|
String str = scope .();
|
|
|
|
TypePrinter<TestType> tp = .();
|
|
|
|
tp.ToString(str);
|
|
|
|
Debug.Assert(str == """
|
|
|
|
0 mX
|
|
|
|
4 mY
|
|
|
|
8 mZ
|
|
|
|
""");
|
2021-12-16 07:28:03 -05:00
|
|
|
|
|
|
|
Foo bar = .(10, 2);
|
|
|
|
ISerializable iSer = bar;
|
|
|
|
SerializationContext serCtx = scope .();
|
|
|
|
iSer.Serialize(serCtx);
|
|
|
|
Test.Assert(serCtx.mStr == "x 10\ny 2\n");
|
2021-01-11 09:41:43 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|