1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-16 15:24:10 +02:00
Beef/IDEHelper/Tests/src/ConstEval.bf
2022-03-31 11:16:13 -07:00

220 lines
4.5 KiB
Beef

using System;
using System.Collections;
using System.Diagnostics;
namespace Tests
{
class ConstEval
{
public enum EnumA
{
case A;
case B(float a, float b);
case C(String str);
public struct Inner
{
public const EnumA cVal = .C("InnerTest");
}
}
struct StructA
{
public int32 mA;
public int32 mB;
public static int32 sVal = 1000;
public this(int32 a, int32 b)
{
mA = a + sVal;
mB = b;
}
}
struct ZeroStruct
{
public this() { }
public const ZeroStruct ConstValue = ZeroStruct();
}
const String cStrA = "Abc";
const String cStrB = GetStringA(cStrA, 12, 23);
// Comptime attribute means this method will always be const-evaluated
[Comptime]
static String GetStringA(String str, int a, int b)
{
// Const-eval functions can return scope-allocated data
return scope $"{str}:{a}:{b}";
}
static int32 Factorial(int32 n)
{
return n <= 1 ? 1 : (n * Factorial(n - 1));
}
static int32 Fibonacci(int32 n)
{
return n <= 1 ? n : Fibonacci(n - 1) + Fibonacci(n - 2);
}
public static String GetTypeDesc<T>()
{
String str = scope .();
T val = default;
val.GetType().GetFullName(str);
str.Append(" ");
for (var fieldInfo in typeof(T).GetFields())
{
if (!fieldInfo.IsInstanceField)
continue;
if (@fieldInfo.Index > 0)
str.Append(", ");
fieldInfo.FieldType.GetFullName(str);
str.Append(" ");
str.Append(fieldInfo.Name);
}
return str;
}
public static Span<int32> GetSorted(String numList)
{
List<int32> list = scope .();
for (var sv in numList.Split(','))
{
sv.Trim();
if (int32.Parse(sv) case .Ok(let val))
list.Add(val);
}
list.Sort();
return list;
}
public static int32 MethodA()
{
mixin Add10(var a)
{
a += 10
}
int32 a = 1;
void Inc()
{
a++;
}
for (int i < 2)
{
defer { a *= 2; }
Inc();
Add10!(a);
}
return a;
}
// This method can only be const evaluated
[Comptime]
public static int32 ConstSum(params int32[] vals)
{
int32 sum = 0;
for (let val in vals)
sum += val;
return sum;
}
public static int32 MethodB()
{
// Returns different results depending on whether we are comptime
return Compiler.IsComptime ? 1 : 0;
}
public static int32 MethodC(StructA sa = .(1, 2), (int32, int32) tup = (20, 30), int32[2] arr = .(300, 400))
{
return sa.mA + sa.mB + tup.0 + tup.1 + arr[0] + arr[1];
}
[Comptime(ConstEval=true)]
static var StrToValue(String str)
{
if (str.Contains('.'))
return float.Parse(str).Value;
return int.Parse(str).Value;
}
class ClassA
{
public const let cVal0 = StrToValue("123");
public const let cVal1 = StrToValue("1.23");
}
[Comptime]
static int StrLenMixin(StringView str)
{
mixin test()
{
str.Length
}
return test!();
}
static String EnumAToStr(EnumA ea)
{
return ea.ToString(.. new .());
}
[Test]
public static void TestBasics()
{
Test.Assert(ClassA.cVal0 == 123);
Test.Assert(Math.Abs(ClassA.cVal1 - 1.23) < 0.0001);
const int fac = Factorial(8);
Test.Assert(fac == 40320);
const int fib = Fibonacci(27);
Test.Assert(fib == 196418);
// Generated string has reference equality to equivalent literal
Test.Assert(cStrB === "Abc:12:23");
const String strC = GetTypeDesc<StructA>();
Test.Assert(strC === "Tests.ConstEval.StructA int32 mA, int32 mB");
// Const Span<T> results can be used to initialize statically-sized arrays
const int32[?] iArr = GetSorted("8, 1, 3, 7");
Compiler.Assert(iArr == .(1, 3, 7, 8));
Test.Assert(iArr == .(1, 3, 7, 8));
let val0 = [ConstEval]MethodA();
Compiler.Assert(val0 == 70);
let val1 = MethodA();
// 'val1' is a read-only variable, but not const, so the following line would fail
//Compiler.Assert(val1 == 24);
Test.Assert(val1 == 70);
// This method is marked as Comptime so it always evaluates as const
let val2 = ConstSum(3, 20, 100);
Compiler.Assert(val2 == 123);
Test.Assert(MethodB() == 0);
Test.Assert([ConstEval]MethodB() == 1);
Test.Assert(MethodC() == 1753);
Test.Assert(StrLenMixin("ABCD") == 4);
String s1 = [ConstEval]EnumAToStr(.C("Test1"));
Test.Assert(s1 === "C(\"Test1\")");
const String s2 = EnumAToStr(.C("Test2"));
Test.Assert(s2 === "C(\"Test2\")");
const String s3 = EnumAToStr(.B(1, 2));
Test.Assert(s3 === "B(1, 2)");
const let s4 = EnumAToStr(EnumA.Inner.cVal);
Test.Assert(s4 === "C(\"InnerTest\")");
}
}
}