1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 11:38:21 +02:00
Beef/BeefLibs/corlib/src/Compiler.bf
2021-12-11 09:08:42 -08:00

296 lines
7.5 KiB
Beef

using System.Reflection;
using System.Diagnostics;
using System.Collections;
using System.Security.Cryptography;
namespace System
{
static class Compiler
{
public abstract class Generator
{
public enum Flags
{
None = 0,
AllowRegenerate = 1
}
public String mCmdInfo = new String() ~ delete _;
public Dictionary<StringView, StringView> mParams = new .() ~ delete _;
public abstract String Name { get; }
public StringView ProjectName => mParams["ProjectName"];
public StringView ProjectDir => mParams["ProjectDir"];
public StringView FolderDir => mParams["FolderDir"];
public StringView Namespace => mParams["Namespace"];
public StringView DefaultNamespace => mParams["DefaultNamespace"];
public StringView WorkspaceName => mParams["WorkspaceName"];
public StringView WorkspaceDir => mParams["WorkspaceDir"];
public StringView DateTime => mParams["DateTime"];
public void Fail(StringView error)
{
mCmdInfo.AppendF("error\t");
error.QuoteString(mCmdInfo);
mCmdInfo.Append("\n");
}
public void AddEdit(StringView dataName, StringView label, StringView defaultValue)
{
mCmdInfo.AppendF($"addEdit\t");
dataName.QuoteString(mCmdInfo);
mCmdInfo.Append("\t");
label.QuoteString(mCmdInfo);
mCmdInfo.Append("\t");
defaultValue.QuoteString(mCmdInfo);
mCmdInfo.Append("\n");
}
public void AddCombo(StringView dataName, StringView label, StringView defaultValue, Span<StringView> values)
{
mCmdInfo.AppendF($"addCombo\t");
dataName.QuoteString(mCmdInfo);
mCmdInfo.Append("\t");
label.QuoteString(mCmdInfo);
mCmdInfo.Append("\t");
defaultValue.QuoteString(mCmdInfo);
for (var value in values)
{
mCmdInfo.Append("\t");
value.QuoteString(mCmdInfo);
}
mCmdInfo.Append("\n");
}
public void AddCheckbox(StringView dataName, StringView label, bool defaultValue)
{
mCmdInfo.AppendF($"addCheckbox\t");
dataName.QuoteString(mCmdInfo);
mCmdInfo.Append("\t");
label.QuoteString(mCmdInfo);
mCmdInfo.AppendF($"\t{defaultValue}\n");
}
public bool GetString(StringView key, String outVal)
{
if (mParams.TryGetAlt(key, var matchKey, var value))
{
outVal.Append(value);
return true;
}
return false;
}
public virtual void InitUI()
{
}
public virtual void Generate(String outFileName, String outText, ref Flags generateFlags)
{
}
static String GetName<T>() where T : Generator
{
T val = scope T();
String str = val.Name;
return str;
}
void HandleArgs(String args)
{
for (var line in args.Split('\n', .RemoveEmptyEntries))
{
int tabPos = line.IndexOf('\t');
var key = line.Substring(0, tabPos);
var value = line.Substring(tabPos + 1);
if (mParams.TryAdd(key, var keyPtr, var valuePtr))
{
*keyPtr = key;
*valuePtr = value;
}
}
}
static String InitUI<T>(String args) where T : Generator
{
T val = scope T();
val.HandleArgs(args);
val.InitUI();
return val.mCmdInfo;
}
static String Generate<T>(String args) where T : Generator
{
T val = scope T();
val.HandleArgs(args);
String fileName = scope .();
String outText = scope .();
Flags flags = .None;
val.Generate(fileName, outText, ref flags);
val.mCmdInfo.Append("fileName\t");
fileName.QuoteString(val.mCmdInfo);
val.mCmdInfo.Append("\n");
val.mCmdInfo.Append("data\n");
if (flags.HasFlag(.AllowRegenerate))
{
bool writeArg = false;
for (var line in args.Split('\n', .RemoveEmptyEntries))
{
int tabPos = line.IndexOf('\t');
var key = line.Substring(0, tabPos);
var value = line.Substring(tabPos + 1);
if (key == "Generator")
writeArg = true;
if (writeArg)
{
val.mCmdInfo.AppendF($"// {key}={value}\n");
}
}
var hash = MD5.Hash(.((.)outText.Ptr, outText.Length));
val.mCmdInfo.AppendF($"// GenHash={hash}\n\n");
}
val.mCmdInfo.Append(outText);
return val.mCmdInfo;
}
}
public class NewClassGenerator : Generator
{
public override String Name => "New Class";
public override void InitUI()
{
AddEdit("name", "Class Name", "");
}
public override void Generate(String outFileName, String outText, ref Flags generateFlags)
{
var name = mParams["name"];
if (name.EndsWith(".bf", .OrdinalIgnoreCase))
name.RemoveFromEnd(3);
outFileName.Append(name);
outText.AppendF(
$"""
namespace {Namespace}
{{
class {name}
{{
}}
}}
""");
}
}
public struct MethodBuilder
{
void* mNative;
public void Emit(String str)
{
Comptime_MethodBuilder_EmitStr(mNative, str);
}
public void Emit(Type type)
{
}
}
public static class Options
{
[LinkName("#AllocStackCount")]
public static extern int32 AllocStackCount;
}
[LinkName("#CallerLineNum")]
public static extern int CallerLineNum;
[LinkName("#CallerFilePath")]
public static extern String CallerFilePath;
[LinkName("#CallerFileName")]
public static extern String CallerFileName;
[LinkName("#CallerFileDir")]
public static extern String CallerFileDir;
[LinkName("#CallerMemberName")]
public static extern String CallerMemberName;
[LinkName("#CallerProject")]
public static extern String CallerProject;
[LinkName("#CallerExpression")]
public static extern String[0x00FFFFFF] CallerExpression;
[LinkName("#ProjectName")]
public static extern String ProjectName;
[LinkName("#ModuleName")]
public static extern String ModuleName;
[LinkName("#TimeLocal")]
public static extern String TimeLocal;
[LinkName("#IsComptime")]
public static extern bool IsComptime;
[LinkName("#IsBuilding")]
public static extern bool IsBuilding;
[LinkName("#IsReified")]
public static extern bool IsReified;
[LinkName("#CompileRev")]
public static extern int32 CompileRev;
[Comptime]
public static void Assert(bool cond)
{
if (!cond)
Runtime.FatalError("Assert failed");
}
static extern void* Comptime_MethodBuilder_EmitStr(void* native, StringView str);
static extern void* Comptime_CreateMethod(int32 typeId, StringView methodName, Type returnType, MethodFlags methodFlags);
static extern void Comptime_EmitTypeBody(int32 typeId, StringView text);
static extern void Comptime_EmitMethodEntry(int64 methodHandle, StringView text);
static extern void Comptime_EmitMethodExit(int64 methodHandle, StringView text);
static extern void Comptime_EmitMixin(StringView text);
[Comptime(OnlyFromComptime=true)]
public static MethodBuilder CreateMethod(Type owner, StringView methodName, Type returnType, MethodFlags methodFlags)
{
MethodBuilder builder = .();
builder.[Friend]mNative = Comptime_CreateMethod((.)owner.TypeId, methodName, returnType, methodFlags);
return builder;
}
[Comptime(OnlyFromComptime=true)]
public static void EmitTypeBody(Type owner, StringView text)
{
Comptime_EmitTypeBody((.)owner.TypeId, text);
}
[Comptime(OnlyFromComptime=true)]
public static void EmitMethodEntry(ComptimeMethodInfo methodHandle, StringView text)
{
Comptime_EmitMethodEntry(methodHandle.mNativeMethodInstance, text);
}
[Comptime(OnlyFromComptime=true)]
public static void EmitMethodExit(ComptimeMethodInfo methodHandle, StringView text)
{
Comptime_EmitMethodExit(methodHandle.mNativeMethodInstance, text);
}
[Comptime]
public static void Mixin(StringView text)
{
if (Compiler.IsComptime)
Comptime_EmitMixin(text);
}
}
}