1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 19:48:20 +02:00

Code generator support

This commit is contained in:
Brian Fiete 2021-12-11 09:08:42 -08:00
parent 195c705a46
commit 73099e4a04
15 changed files with 1472 additions and 83 deletions

View file

@ -256,7 +256,10 @@ namespace Beefy.widgets
public virtual void PopupWindow(WidgetWindow parentWindow, float offsetX = 0, float offsetY = 0)
{
if (mClosed)
{
BFApp.sApp.DeferDelete(this);
return;
}
mInPopupWindow = true;

View file

@ -1,8 +1,188 @@
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;
@ -43,7 +223,7 @@ namespace System
public static extern String CallerProject;
[LinkName("#CallerExpression")]
public static extern String[0x0FFFFFFF] CallerExpression;
public static extern String[0x00FFFFFF] CallerExpression;
[LinkName("#ProjectName")]
public static extern String ProjectName;

View file

@ -15,9 +15,10 @@ namespace IDE
public Action mOnThreadDone ~ delete _;
[ThreadStatic]
public static bool mBpSetThreadName;
public bool mAllowFastFinish;
WaitEvent mWaitEvent = new WaitEvent() ~ delete _;
public void DoBackground(ThreadStart threadStart, Action onThreadDone = null, int maxWait = 0)
public void DoBackground(ThreadStart threadStart, Action onThreadDone = null, int maxWait = 0, bool allowFastFinish = true)
{
Debug.Assert(Thread.CurrentThread == IDEApp.sApp.mMainThread);
@ -26,6 +27,7 @@ namespace IDE
BeefPerf.Event("DoBackground:starting", "");
mAllowFastFinish = allowFastFinish;
mOnThreadDone = onThreadDone;
mThreadRunning = true;
mWaitEvent.Reset();
@ -47,6 +49,7 @@ namespace IDE
delete threadStart;
mThread = null;
mThreadRunning = false;
mAllowFastFinish = true;
BeefPerf.Event("DoBackground:threadEnd", "");
mWaitEvent.Set();
@ -132,7 +135,7 @@ namespace IDE
}
public virtual void RequestFastFinish()
public virtual void RequestFastFinish(bool force = false)
{
}
@ -190,15 +193,20 @@ namespace IDE
return (mThreadWorker.mThreadRunning || mThreadWorkerHi.mThreadRunning);
}
public bool IsPerformingBackgroundOperationHi()
{
return (mThreadWorkerHi.mThreadRunning);
}
public void DoBackground(ThreadStart threadStart, Action onThreadDone = null, int maxWait = 0)
{
CancelBackground();
mThreadWorker.DoBackground(threadStart, onThreadDone, maxWait);
}
public void DoBackgroundHi(ThreadStart threadStart, Action onThreadDone = null)
public void DoBackgroundHi(ThreadStart threadStart, Action onThreadDone = null, bool allowFastFinish = true)
{
mThreadWorkerHi.DoBackground(threadStart, onThreadDone);
mThreadWorkerHi.DoBackground(threadStart, onThreadDone, 0, allowFastFinish);
}
public void CheckThreadDone()

View file

@ -94,6 +94,15 @@ namespace IDE.Compiler
[CallingConvention(.Stdcall), CLink]
static extern char8* BfCompiler_GetUsedOutputFileNames(void* bfCompiler, void* bfProject, bool flushQueuedHotFiles, out bool hadOutputChanges);
[CallingConvention(.Stdcall), CLink]
static extern char8* BfCompiler_GetGeneratorTypeDefList(void* bfCompiler);
[CallingConvention(.Stdcall), CLink]
static extern char8* BfCompiler_GetGeneratorInitData(void* bfCompiler, char8* typeDefName, char8* args);
[CallingConvention(.Stdcall), CLink]
static extern char8* BfCompiler_GetGeneratorGenData(void* bfCompiler, char8* typeDefName, char8* args);
[CallingConvention(.Stdcall), CLink]
static extern char8* BfCompiler_GetTypeDefList(void* bfCompiler);
@ -674,17 +683,21 @@ namespace IDE.Compiler
public override void RequestCancelBackground()
{
if ([Friend]mThreadWorker.mThreadRunning)
if (mThreadWorker.mThreadRunning)
{
if ((mNativeBfCompiler != null) && (!gApp.mDeterministic))
BfCompiler_Cancel(mNativeBfCompiler);
}
}
public override void RequestFastFinish()
public override void RequestFastFinish(bool force = false)
{
if ([Friend]mThreadWorker.mThreadRunning || [Friend]mThreadWorkerHi.mThreadRunning)
if (mThreadWorker.mThreadRunning || mThreadWorkerHi.mThreadRunning)
{
if ((!force) &&
((!mThreadWorker.mAllowFastFinish) || (!mThreadWorkerHi.mAllowFastFinish)))
return;
if ((mNativeBfCompiler != null) && (!gApp.mDeterministic))
BfCompiler_RequestFastFinish(mNativeBfCompiler);
}
@ -710,6 +723,21 @@ namespace IDE.Compiler
return BfCompiler_GetCurConstEvalExecuteId(mNativeBfCompiler);
}
public void GetGeneratorTypeDefList(String outStr)
{
outStr.Append(BfCompiler_GetGeneratorTypeDefList(mNativeBfCompiler));
}
public void GetGeneratorInitData(String typeDefName, String args, String outStr)
{
outStr.Append(BfCompiler_GetGeneratorInitData(mNativeBfCompiler, typeDefName, args));
}
public void GetGeneratorGenData(String typeDefName, String args, String outStr)
{
outStr.Append(BfCompiler_GetGeneratorGenData(mNativeBfCompiler, typeDefName, args));
}
public void GetTypeDefList(String outStr)
{
outStr.Append(BfCompiler_GetTypeDefList(mNativeBfCompiler));

View file

@ -37,6 +37,7 @@ namespace IDE
public ProjectFolder mParentFolder;
public String mName = new String() ~ delete _;
public String mComment = new String() ~ delete _;
public bool mDetached;
public virtual bool IncludeInMap
{
@ -105,6 +106,7 @@ namespace IDE
public virtual void Detach()
{
mDetached = true;
ReleaseRef();
}
}

View file

@ -598,10 +598,14 @@ namespace IDE.ui
}
}
var bfSystem = gApp.mBfResolveSystem;
String typeName = scope .();
GetName(item, typeName);
String info = scope .();
bfSystem.Lock(0);
gApp.mBfResolveCompiler.GetTypeDefInfo(typeName, info);
bfSystem.Unlock();
for (let str in info.Split('\n'))
{

View file

@ -0,0 +1,869 @@
using Beefy.theme.dark;
using Beefy.widgets;
using System;
using System.Collections;
using Beefy.gfx;
using Beefy.events;
using IDE.Compiler;
using System.Threading;
using System.Security.Cryptography;
using Beefy.theme;
namespace IDE.ui
{
class GenerateListView : DarkListView
{
public GenerateDialog mNewClassDialog;
}
class GenerateKindBar : DarkComboBox
{
public class Entry
{
public String mTypeName ~ delete _;
public String mName ~ delete _;
}
public static Dictionary<String, int32> sMRU = new Dictionary<String, int32>() ~ delete _;
public static int32 sCurrentMRUIndex = 1;
public GenerateDialog mNewClassDialog;
public List<Entry> mEntries = new List<Entry>() ~ DeleteContainerAndItems!(_);
public List<Entry> mShownEntries = new List<Entry>() ~ delete _;
public String mFilterString ~ delete _;
public String mCurLocation = new String() ~ delete _;
public bool mIgnoreChange = false;
public this(GenerateDialog dialog)
{
mNewClassDialog = dialog;
mLabelAlign = FontAlign.Left;
Label = "";
mLabelX = GS!(16);
mPopulateMenuAction.Add(new => PopulateNavigationBar);
MakeEditable();
mEditWidget.mOnContentChanged.Add(new => NavigationBarChanged);
mEditWidget.mOnGotFocus.Add(new (widget) => mEditWidget.mEditWidgetContent.SelectAll());
mEditWidget.mEditWidgetContent.mWantsUndo = false;
mEditWidget.mOnSubmit.Add(new => mNewClassDialog.[Friend]EditSubmitHandler);
mFocusDropdown = false;
}
public ~this()
{
}
static ~this()
{
for (var key in sMRU.Keys)
delete key;
}
public void SetLocation(String location)
{
if (mCurMenuWidget == null)
{
mIgnoreChange = true;
mEditWidget.SetText(location);
mEditWidget.mEditWidgetContent.SelectAll();
// SetText can attempt to scroll to the right to make the cursor position visible. Just scroll back to the start.
mEditWidget.HorzScrollTo(0);
//mNewClassDialog.SelectKind();
mIgnoreChange = false;
}
}
private void PopulateNavigationBar(Menu menu)
{
List<StringView> findStrs = null;
if (mFilterString != null)
findStrs = scope:: List<StringView>(mFilterString.Split(' '));
EntryLoop: for (int32 entryIdx = 0; entryIdx < mEntries.Count; entryIdx++)
{
var entry = mEntries[entryIdx];
if (findStrs != null)
{
for (let findStr in findStrs)
{
if (entry.mName.IndexOf(findStr, true) == -1)
continue EntryLoop;
}
}
mShownEntries.Add(entry);
var menuItem = menu.AddItem(entry.mName);
menuItem.mOnMenuItemSelected.Add(new (evt) =>
{
mNewClassDialog.mPendingUIFocus = true;
ShowEntry(entryIdx, entry);
});
}
}
void ShowEntry(int32 entryIdx, Entry entry)
{
mEditWidget.SetText(entry.mName);
mEditWidget.mEditWidgetContent.SelectAll();
mCurMenuWidget?.Close();
}
private void NavigationBarChanged(EditEvent theEvent)
{
if (mIgnoreChange)
return;
var editWidget = (EditWidget)theEvent.mSender;
var searchText = scope String();
editWidget.GetText(searchText);
searchText.Trim();
mFilterString = searchText;
ShowDropdown();
mFilterString = null;
}
bool mIgnoreShowDropdown;
public override MenuWidget ShowDropdown()
{
if (mIgnoreShowDropdown)
return null;
mIgnoreShowDropdown = true;
defer { mIgnoreShowDropdown = false; }
if (!mEditWidget.mHasFocus)
SetFocus();
if (mFilterString == null)
mEditWidget.Content.SelectAll();
mShownEntries.Clear();
base.ShowDropdown();
int32 bestItem = -1;
int32 bestPri = -1;
var menuWidget = (DarkMenuWidget)mCurMenuWidget;
for (int32 itemIdx = 0; itemIdx < menuWidget.mItemWidgets.Count; itemIdx++)
{
var menuItemWidget = (DarkMenuItem)menuWidget.mItemWidgets[itemIdx];
int32 pri;
sMRU.TryGetValue(menuItemWidget.mMenuItem.mLabel, out pri);
if (pri > bestPri)
{
bestItem = itemIdx;
bestPri = pri;
}
}
if (bestItem != -1)
{
mCurMenuWidget.mOnSelectionChanged.Add(new => SelectionChanged);
mCurMenuWidget.SetSelection(bestItem);
}
return menuWidget;
}
void SelectionChanged(int selIdx)
{
if (mEditWidget.mEditWidgetContent.HasSelection())
{
bool prevIgnoreShowDropdown = mIgnoreShowDropdown;
mIgnoreShowDropdown = true;
mEditWidget.SetText("");
mIgnoreShowDropdown = prevIgnoreShowDropdown;
}
}
public override void MenuClosed()
{
}
}
class GenerateDialog : IDEDialog
{
public class UIEntry
{
public String mName ~ delete _;
public String mData ~ delete _;
public String mLabel ~ delete _;
public Widget mWidget;
}
public enum ThreadState
{
None,
Executing,
Done
}
public bool mPendingGenList;
public GenerateKindBar mKindBar;
public ThreadState mThreadState;
public int mThreadWaitCount;
public String mNamespace ~ delete _;
public String mProjectName ~ delete _;
public ProjectItem mProjectItem ~ _.ReleaseRef();
public String mFolderPath ~ delete _;
public List<UIEntry> mUIEntries = new .() ~ DeleteContainerAndItems!(_);
public GenerateKindBar.Entry mSelectedEntry;
public GenerateKindBar.Entry mPendingSelectedEntry;
public String mUIData ~ delete _;
public float mUIHeight = 0;
public OutputPanel mOutputPanel;
public bool mPendingUIFocus;
public bool mSubmitting;
public bool mSubmitQueued;
public bool mRegenerating;
public this(ProjectItem projectItem, bool allowHashMismatch = false)
{
var project = projectItem.mProject;
mProjectItem = projectItem;
mProjectItem.AddRef();
mNamespace = new .();
var projectFolder = projectItem as ProjectFolder;
var projectSource = projectItem as ProjectSource;
if (projectSource != null)
{
projectFolder = projectSource.mParentFolder;
mRegenerating = true;
}
projectFolder.GetRelDir(mNamespace); mNamespace.Replace('/', '.'); mNamespace.Replace('\\', '.'); mNamespace.Replace(" ", "");
if (mNamespace.StartsWith("src."))
{
mNamespace.Remove(0, 4);
if (!project.mBeefGlobalOptions.mDefaultNamespace.IsWhiteSpace)
{
mNamespace.Insert(0, ".");
mNamespace.Insert(0, project.mBeefGlobalOptions.mDefaultNamespace);
}
}
else if (projectItem.mParentFolder == null)
{
mNamespace.Clear();
mNamespace.Append(project.mBeefGlobalOptions.mDefaultNamespace);
}
else
mNamespace.Clear();
mFolderPath = projectFolder.GetFullImportPath(.. new .());
mProjectName = new String(projectItem.mProject.mProjectName);
mWindowFlags = .ClientSized | .TopMost | .Caption | .Border | .SysMenu | .Resizable | .PopupPosition;
AddOkCancelButtons(new (evt) => { CreateClass(); }, null, 0, 1);
Title = "Generate";
mKindBar = new GenerateKindBar(this);
AddWidget(mKindBar);
mKindBar.mEditWidget.mOnContentChanged.Add(new (theEvent) => { SelectKind(); });
if (mRegenerating)
{
mSubmitQueued = true;
mKindBar.SetVisible(false);
SourceViewPanel sourceViewPanel = gApp.ShowProjectItem(projectSource, false);
String filePath = projectSource.GetFullImportPath(.. scope .());
String text = scope .();
sourceViewPanel.mEditWidget.GetText(text);
StringView generatorName = default;
StringView hash = default;
int dataIdx = -1;
for (var line in text.Split('\n'))
{
if (!line.StartsWith("// "))
{
dataIdx = @line.MatchPos + 1;
break;
}
int eqPos = line.IndexOf('=');
if (eqPos == -1)
break;
StringView key = line.Substring(3, eqPos - 3);
StringView value = line.Substring(eqPos + 1);
if (key == "Generator")
generatorName = value;
else if (key == "GenHash")
hash = value;
else
{
UIEntry uiEntry = new .();
uiEntry.mName = new .(key);
uiEntry.mData = new .(value);
mUIEntries.Add(uiEntry);
}
}
if ((generatorName == default) || (hash == default))
{
Close();
gApp.Fail(scope $"File '{filePath}' was not generated by a generator that include regeneration information");
return;
}
if ((dataIdx != -1) && (!allowHashMismatch))
{
var origHash = MD5Hash.Parse(hash).GetValueOrDefault();
StringView dataStr = text.Substring(dataIdx);
var checkHash = MD5.Hash(.((.)dataStr.Ptr, dataStr.Length));
if (origHash != checkHash)
{
Close();
Dialog dialog = ThemeFactory.mDefault.CreateDialog("Regenerate?", "This file has been modified since it was generated. Are you sure you want to regenerate?", DarkTheme.sDarkTheme.mIconWarning);
dialog.AddButton("Yes", new (evt) =>
{
gApp.mProjectPanel.Regenerate(true);
//dialog.Close();
});
dialog.AddButton("No", new (evt) =>
{
//dialog.Close();
});
dialog.PopupWindow(gApp.GetActiveWindow());
return;
}
}
GenerateKindBar.Entry entry = new .();
entry.mName = new .(generatorName);
entry.mTypeName = new .(generatorName);
mKindBar.mEntries.Add(entry);
mPendingSelectedEntry = entry;
}
else
mPendingGenList = true;
mKindBar.mMouseVisible = false;
mTabWidgets.Add(mKindBar.mEditWidget);
}
public ~this()
{
var bfCompiler = gApp.mBfResolveCompiler;
if (mThreadState == .Executing)
{
bfCompiler.WaitForBackground();
}
}
public void SelectKind()
{
GenerateKindBar.Entry foundEntry = null;
String text = mKindBar.mEditWidget.GetText(.. scope .());
for (var entry in mKindBar.mEntries)
if (entry.mName == text)
foundEntry = entry;
if (foundEntry == null)
return;
if (mSelectedEntry == foundEntry)
return;
mPendingSelectedEntry = foundEntry;
}
public void ThreadProc()
{
var bfSystem = gApp.mBfResolveSystem;
var bfCompiler = gApp.mBfResolveCompiler;
String outStr = scope String();
bfSystem.Lock(0);
defer bfSystem.Unlock();
if (mSelectedEntry != null)
{
String args = scope .();
var project = gApp.mWorkspace.FindProject(mProjectName);
if (project == null)
return;
using (gApp.mMonitor.Enter())
{
args.AppendF(
$"""
ProjectName\t{mProjectName}
ProjectDir\t{project.mProjectPath}
FolderDir\t{mFolderPath}
Namespace\t{mNamespace}
DefaultNamespace\t{project.mBeefGlobalOptions.mDefaultNamespace}
WorkspaceName\t{gApp.mWorkspace.mName}
WorkspaceDir\t{gApp.mWorkspace.mDir}
DateTime\t{DateTime.Now}
""");
if (mSubmitting)
{
args.AppendF($"Generator\t{mSelectedEntry.mTypeName}\n");
for (var uiEntry in mUIEntries)
{
String data = scope .();
if (uiEntry.mData != null)
{
data.Append(uiEntry.mData);
}
else if (var editWidget = uiEntry.mWidget as EditWidget)
{
editWidget.GetText(data);
}
else if (var comboBox = uiEntry.mWidget as DarkComboBox)
{
comboBox.GetLabel(data);
}
else if (var checkBox = uiEntry.mWidget as CheckBox)
{
checkBox.Checked.ToString(data);
}
data.Replace('\n', '\r');
args.AppendF($"{uiEntry.mName}\t{data}\n");
}
}
}
mUIData = new String();
if (mSubmitting)
bfCompiler.GetGeneratorGenData(mSelectedEntry.mTypeName, args, mUIData);
else
bfCompiler.GetGeneratorInitData(mSelectedEntry.mTypeName, args, mUIData);
}
else
{
bfCompiler.GetGeneratorTypeDefList(outStr);
for (var line in outStr.Split('\n', .RemoveEmptyEntries))
{
if (line.StartsWith("!error"))
{
ShowError(line.Substring(7));
continue;
}
var entry = new GenerateKindBar.Entry();
var partItr = line.Split('\t');
entry.mTypeName = new String(partItr.GetNext().Value);
if (partItr.GetNext() case .Ok(let val))
entry.mName = new String(val);
else
{
entry.mName = new String(entry.mTypeName);
int termPos = entry.mName.LastIndexOf('.');
if (termPos != -1)
entry.mName.Remove(0, termPos + 1);
termPos = entry.mName.LastIndexOf('+');
if (termPos != -1)
entry.mName.Remove(0, termPos + 1);
}
mKindBar.mEntries.Add(entry);
}
}
}
public override void CalcSize()
{
mWidth = GS!(320);
mHeight = GS!(96);
mMinWidth = mWidth;
}
protected override void RehupMinSize()
{
mWidgetWindow.SetMinimumSize(GS!(240), (.)mUIHeight + GS!(24), true);
}
void CreateClass()
{
//mClassViewPanel.[Friend]mSearchEdit.mOnSubmit(null);
}
void ShowError(StringView error)
{
if (mOutputPanel == null)
{
mOutputPanel = new OutputPanel();
AddWidget(mOutputPanel);
ResizeComponents();
}
String str = scope .();
str.Append(error);
str.Replace('\r', '\n');
str.Append("\n");
mOutputPanel.WriteSmart(str);
}
public override void Update()
{
base.Update();
if ((!mKindBar.mEditWidget.mHasFocus) && (mWidgetWindow.mHasFocus))
{
var sel = mPendingSelectedEntry ?? mSelectedEntry;
String editText = mKindBar.mEditWidget.GetText(.. scope .());
if ((sel != null) && (editText != sel.mName))
{
mKindBar.mIgnoreChange = true;
mKindBar.mEditWidget.SetText(sel.mName);
mKindBar.mIgnoreChange = false;
}
}
if (mThreadState == .Done)
{
if (mSelectedEntry != null)
{
List<UIEntry> oldEntries = scope .();
Dictionary<String, UIEntry> entryMap = scope .();
if (!mSubmitting)
{
for (var uiEntry in mUIEntries)
{
if (!entryMap.TryAdd(uiEntry.mName, uiEntry))
oldEntries.Add(uiEntry);
}
mUIEntries.Clear();
}
if (mUIData != null)
{
if (mOutputPanel != null)
{
mOutputPanel.RemoveSelf();
DeleteAndNullify!(mOutputPanel);
}
String fileName = default;
StringView genText = default;
bool hadError = false;
if (mUIData.IsEmpty)
{
gApp.Fail("Generator failed to return results");
}
LinesLoop: for (var line in mUIData.Split('\n', .RemoveEmptyEntries))
{
var partItr = line.Split('\t');
var kind = partItr.GetNext().Value;
switch (kind)
{
case "!error":
ShowError(line.Substring(7));
case "addEdit":
if (mSubmitting)
break;
UIEntry uiEntry = new UIEntry();
uiEntry.mName = partItr.GetNext().Value.UnQuoteString(.. new .());
uiEntry.mLabel = partItr.GetNext().Value.UnQuoteString(.. new .());
var defaultValue = partItr.GetNext().Value.UnQuoteString(.. scope .());
DarkEditWidget editWidget = new DarkEditWidget();
uiEntry.mWidget = editWidget;
editWidget.SetText(defaultValue);
editWidget.mEditWidgetContent.SelectAll();
editWidget.mOnSubmit.Add(new => EditSubmitHandler);
AddWidget(editWidget);
mUIEntries.Add(uiEntry);
mTabWidgets.Add(editWidget);
case "addCombo":
if (mSubmitting)
break;
UIEntry uiEntry = new UIEntry();
uiEntry.mName = partItr.GetNext().Value.UnQuoteString(.. new .());
uiEntry.mLabel = partItr.GetNext().Value.UnQuoteString(.. new .());
var defaultValue = partItr.GetNext().Value.UnQuoteString(.. scope .());
List<String> choices = new List<String>();
DarkComboBox comboBox = new DarkComboBox();
while (partItr.GetNext() case .Ok(let val))
{
choices.Add(val.UnQuoteString(.. new .()));
}
comboBox.mOnDeleted.Add(new (widget) => { DeleteContainerAndItems!(choices); });
comboBox.mPopulateMenuAction.Add(new (menu) =>
{
for (var choice in choices)
{
var item = menu.AddItem(choice);
item.mOnMenuItemSelected.Add(new (menu) =>
{
comboBox.Label = menu.mLabel;
});
}
});
uiEntry.mWidget = comboBox;
comboBox.Label = defaultValue;
AddWidget(comboBox);
mUIEntries.Add(uiEntry);
mTabWidgets.Add(comboBox);
case "addCheckbox":
if (mSubmitting)
break;
UIEntry uiEntry = new UIEntry();
uiEntry.mName = partItr.GetNext().Value.UnQuoteString(.. new .());
uiEntry.mLabel = partItr.GetNext().Value.UnQuoteString(.. new .());
var defaultValue = partItr.GetNext().Value;
DarkCheckBox checkbox = new DarkCheckBox();
uiEntry.mWidget = checkbox;
checkbox.Label = uiEntry.mLabel;
checkbox.Checked = defaultValue == "True";
AddWidget(checkbox);
mUIEntries.Add(uiEntry);
mTabWidgets.Add(checkbox);
case "error":
hadError = true;
gApp.Fail(line.Substring(6).UnQuoteString(.. scope .()));
case "fileName":
fileName = line.Substring(9).UnQuoteString(.. scope:: .());
case "options":
case "data":
genText = .(mUIData, @line.MatchPos + 1);
break LinesLoop;
}
}
ResizeComponents();
RehupMinSize();
if (fileName?.EndsWith(".bf", .OrdinalIgnoreCase) == true)
fileName.RemoveFromEnd(3);
if ((fileName != null) && (!mRegenerating))
{
for (char8 c in fileName.RawChars)
{
if (!c.IsLetterOrDigit)
{
gApp.Fail(scope $"Invalid generated file name: {fileName}");
hadError = true;
break;
}
}
if (fileName.IsEmpty)
{
gApp.Fail("Geneator failed to specify file name");
hadError = true;
}
}
if ((!hadError) && (genText != default) && (fileName != null))
{
if (!mProjectItem.mDetached)
{
if (mRegenerating)
{
gApp.mProjectPanel.Regenerate(mProjectItem as ProjectSource, genText);
}
else
{
gApp.mProjectPanel.Generate(mProjectItem as ProjectFolder, fileName, genText);
}
}
Close();
}
if (mPendingUIFocus)
{
mPendingUIFocus = false;
if (!mUIEntries.IsEmpty)
mUIEntries[0].mWidget.SetFocus();
}
DeleteAndNullify!(mUIData);
}
//
if (mSubmitting)
{
if (!mClosed)
{
mSubmitting = false;
mSubmitQueued = false;
mDefaultButton.mDisabled = false;
mEscButton.mDisabled = false;
}
}
else
{
for (var uiEntry in entryMap.Values)
oldEntries.Add(uiEntry);
for (var uiEntry in oldEntries)
{
mTabWidgets.Remove(uiEntry.mWidget);
uiEntry.mWidget.RemoveSelf();
DeleteAndNullify!(uiEntry.mWidget);
}
ClearAndDeleteItems(oldEntries);
}
}
else
{
mKindBar.mMouseVisible = true;
mKindBar.SetFocus();
mKindBar.SetLocation("New Class");
}
mThreadState = .None;
MarkDirty();
}
bool isWorking = false;
if (mThreadState == .None)
{
if ((mPendingGenList) || (mPendingSelectedEntry != null))
{
isWorking = true;
var bfCompiler = gApp.mBfResolveCompiler;
if (!bfCompiler.IsPerformingBackgroundOperation())
{
bfCompiler.CheckThreadDone();
mPendingGenList = false;
if (mPendingSelectedEntry != null)
{
if (mSubmitQueued)
mSubmitting = true;
mSelectedEntry = mPendingSelectedEntry;
mPendingSelectedEntry = null;
}
mThreadState = .Executing;
bfCompiler.DoBackgroundHi(new => ThreadProc, new () =>
{
mThreadState = .Done;
}, false);
}
}
}
gApp.mBfResolveCompiler.CheckThreadDone();
if ((mThreadState == .Executing) || (isWorking))
{
mThreadWaitCount++;
if (mUpdateCnt % 8 == 0)
MarkDirty();
}
else
mThreadWaitCount = 0;
}
public override void Resize(float x, float y, float width, float height)
{
base.Resize(x, y, width, height);
ResizeComponents();
//mClassViewPanel.Resize(0, 0, width, height - GS!(34));
}
public override void PopupWindow(WidgetWindow parentWindow, float offsetX = 0, float offsetY = 0)
{
base.PopupWindow(parentWindow, offsetX, offsetY);
//mKindBar.SetFocus();
}
public override void Draw(Graphics g)
{
base.Draw(g);
void DrawLabel(Widget widget, StringView label)
{
if (widget == null)
return;
if (widget is CheckBox)
return;
g.DrawString(label, widget.mX + GS!(6), widget.mY - GS!(20));
}
DrawLabel(mKindBar, mRegenerating ? "Regenerating ..." : "Using Generator");
for (var uiEntry in mUIEntries)
DrawLabel(uiEntry.mWidget, uiEntry.mLabel);
}
public override void DrawAll(Graphics g)
{
base.DrawAll(g);
if (mThreadWaitCount > 10)
{
using (g.PushColor(0x60505050))
g.FillRect(0, 0, mWidth, mHeight - GS!(40));
IDEUtils.DrawWait(g, mWidth/2, mHeight/2, mUpdateCnt);
}
}
public override void ResizeComponents()
{
base.ResizeComponents();
mUIHeight = GS!(32);
float insetSize = GS!(12);
mKindBar.Resize(insetSize, mUIHeight, mWidth - insetSize - insetSize, GS!(22));
mUIHeight += GS!(52);
for (var uiEntry in mUIEntries)
{
if (uiEntry.mWidget == null)
continue;
float height = GS!(22);
if (uiEntry.mWidget is ComboBox)
height = GS!(26);
if (uiEntry.mWidget is CheckBox)
{
mUIHeight -= GS!(20);
height = GS!(20);
}
uiEntry.mWidget.Resize(insetSize, mUIHeight, mWidth - insetSize - insetSize, height);
mUIHeight += height + GS!(28);
}
if (mOutputPanel != null)
{
float startY = mKindBar.mVisible ? GS!(60) : GS!(36);
mOutputPanel.Resize(insetSize, startY, mWidth - insetSize - insetSize, Math.Max(mHeight - startY - GS!(44), GS!(32)));
mUIHeight = Math.Max(mUIHeight, GS!(160));
}
}
public override void Close()
{
if (mThreadState == .Executing)
{
var bfCompiler = gApp.mBfResolveCompiler;
bfCompiler.RequestFastFinish();
bfCompiler.WaitForBackground();
}
base.Close();
}
public override void Submit()
{
mDefaultButton.mDisabled = true;
mEscButton.mDisabled = true;
if (mSubmitQueued)
return;
mSubmitQueued = true;
mPendingSelectedEntry = mPendingSelectedEntry ?? mSelectedEntry;
}
}
}

View file

@ -327,7 +327,7 @@ namespace IDE.ui
int lineIdx = (curLine + lineOfs) % lineCount;
if (content.GotoRefrenceAtLine(lineIdx))
break;
break;
}
}

View file

@ -792,16 +792,96 @@ namespace IDE.ui
}
}
public void NewClass(ProjectFolder folder)
public void GenerateCode(ProjectFolder folder)
{
DarkDialog dialog = (DarkDialog)ThemeFactory.mDefault.CreateDialog("New Class", "Class Name");
/*DarkDialog dialog = (DarkDialog)ThemeFactory.mDefault.CreateDialog("New Class", "Class Name");
dialog.mMinWidth = GS!(300);
dialog.mDefaultButton = dialog.AddButton("OK", new (evt) => DoNewClass(folder, evt));
dialog.mEscButton = dialog.AddButton("Cancel");
dialog.AddEdit("Unnamed");
dialog.PopupWindow(gApp.GetActiveWindow());
dialog.PopupWindow(gApp.GetActiveWindow());*/
var dialog = new GenerateDialog(folder);
dialog.PopupWindow(gApp.GetActiveWindow());
}
public void Regenerate(bool allowHashMismatch)
{
mListView.GetRoot().WithSelectedItems(scope (selectedItem) =>
{
if (mListViewToProjectMap.GetValue(selectedItem) case .Ok(var sourceProjectItem))
{
var dialog = new GenerateDialog(sourceProjectItem, allowHashMismatch);
dialog.PopupWindow(gApp.GetActiveWindow());
}
});
}
public void Regenerate(ProjectSource projectSource, StringView fileText)
{
var sourceViewPanel = gApp.ShowProjectItem(projectSource, false);
sourceViewPanel.mEditWidget.SetText(scope .(fileText));
}
public void Generate(ProjectFolder folder, StringView fileName, StringView fileText)
{
let project = folder.mProject;
if (project.mNeedsCreate)
project.FinishCreate();
String relFileName = scope .(fileName);
if (!relFileName.Contains('.'))
relFileName.Append(".bf");
String fullFilePath = scope String();
String relPath = scope String();
folder.GetRelDir(relPath);
if (relPath.Length > 0)
relPath.Append("/");
relPath.Append(relFileName);
folder.mProject.GetProjectFullPath(relPath, fullFilePath);
String dirName = scope String();
Path.GetDirectoryPath(fullFilePath, dirName);
Directory.CreateDirectory(dirName).IgnoreError();
if (File.Exists(fullFilePath))
{
var error = scope String();
error.AppendF("File '{0}' already exists", fullFilePath);
IDEApp.sApp.Fail(error);
return;
}
if (File.WriteAllText(fullFilePath, fileText) case .Err)
{
var error = scope String();
error.AppendF("Failed to create file '{0}'", fullFilePath);
gApp.Fail(error);
return;
}
ProjectSource projectSource = new ProjectSource();
projectSource.mIncludeKind = (folder.mIncludeKind == .Auto) ? .Auto : .Manual;
projectSource.mName.Set(relFileName);
projectSource.mPath = new String();
folder.mProject.GetProjectRelPath(fullFilePath, projectSource.mPath);
projectSource.mProject = folder.mProject;
projectSource.mParentFolder = folder;
folder.AddChild(projectSource);
let projectItem = AddProjectItem(projectSource);
if (projectItem != null)
{
mListView.GetRoot().SelectItemExclusively(projectItem);
mListView.EnsureItemVisible(projectItem, false);
}
Sort();
if (folder.mIncludeKind != .Auto)
folder.mProject.SetChanged();
gApp.RecordHistoryLocation(true);
gApp.ShowProjectItem(projectSource);
gApp.RecordHistoryLocation(true);
}
void DoNewClass(ProjectFolder folder, DialogEvent evt)
{
Dialog dlg = (Dialog)evt.mSender;
@ -1470,7 +1550,10 @@ namespace IDE.ui
}
if (doReleaseRef)
{
projectItem.mDetached = true;
projectItem.ReleaseRef();
}
//TODO: Defer this, projectItem is needed for a backgrounded QueueProjectSourceRemoved
//delete projectItem;
}
@ -2471,17 +2554,26 @@ namespace IDE.ui
}
});
item = menu.AddItem("New Class...");
item = menu.AddItem("Generate...");
item.mOnMenuItemSelected.Add(new (item) =>
{
var projectFolder = GetSelectedProjectFolder();
if (projectFolder != null)
{
if (CheckProjectModify(projectFolder.mProject))
NewClass(projectFolder);
GenerateCode(projectFolder);
}
});
if ((projectItem != null) && (projectItem is ProjectSource) && (!isProject))
{
item = menu.AddItem("Regenerate");
item.mOnMenuItemSelected.Add(new (item) =>
{
Regenerate(false);
});
}
item = menu.AddItem("Import File...");
item.mOnMenuItemSelected.Add(new (item) => { mImportFileDeferred = true; /* ImportFile();*/ });

View file

@ -420,6 +420,7 @@ BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly)
mInternalTypeDef = NULL;
mPlatformTypeDef = NULL;
mCompilerTypeDef = NULL;
mCompilerGeneratorTypeDef = NULL;
mDiagnosticsDebugTypeDef = NULL;
mIDisposableTypeDef = NULL;
mIIntegerTypeDef = NULL;
@ -6765,6 +6766,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
mInternalTypeDef = _GetRequiredType("System.Internal");
mPlatformTypeDef = _GetRequiredType("System.Platform");
mCompilerTypeDef = _GetRequiredType("System.Compiler");
mCompilerGeneratorTypeDef = _GetRequiredType("System.Compiler.Generator");
mDiagnosticsDebugTypeDef = _GetRequiredType("System.Diagnostics.Debug");
mIDisposableTypeDef = _GetRequiredType("System.IDisposable");
mIIntegerTypeDef = _GetRequiredType("System.IInteger");
@ -8087,6 +8089,149 @@ String BfCompiler::GetTypeDefList()
return result;
}
String BfCompiler::GetGeneratorString(BfTypeDef* typeDef, BfTypeInstance* typeInst, const StringImpl& generatorMethodName, const StringImpl* args)
{
if (typeInst == NULL)
{
auto type = mContext->mUnreifiedModule->ResolveTypeDef(typeDef, BfPopulateType_BaseType);
if (type != NULL)
typeInst = type->ToTypeInstance();
if (typeInst == NULL)
return "";
}
BfTypeVector typeVector;
typeVector.Add(typeInst);
auto generatorTypeInst = mContext->mUnreifiedModule->ResolveTypeDef(mCompilerGeneratorTypeDef)->ToTypeInstance();
auto methodDef = generatorTypeInst->mTypeDef->GetMethodByName(generatorMethodName);
auto moduleMethodInstance = mContext->mUnreifiedModule->GetMethodInstance(generatorTypeInst, methodDef, typeVector);
SetAndRestoreValue<BfMethodInstance*> prevMethodInstance(mContext->mUnreifiedModule->mCurMethodInstance, moduleMethodInstance.mMethodInstance);
SetAndRestoreValue<BfTypeInstance*> prevTypeInstance(mContext->mUnreifiedModule->mCurTypeInstance, typeInst);
BfExprEvaluator exprEvaluator(mContext->mUnreifiedModule);
exprEvaluator.mBfEvalExprFlags = BfEvalExprFlags_Comptime;
SizedArray<BfIRValue, 1> irArgs;
if (args != NULL)
irArgs.Add(mContext->mUnreifiedModule->GetStringObjectValue(*args));
auto callResult = exprEvaluator.CreateCall(NULL, moduleMethodInstance.mMethodInstance, moduleMethodInstance.mFunc, false, irArgs, NULL, BfCreateCallFlags_None);
if (callResult.mValue.IsConst())
{
auto stringPtr = mContext->mUnreifiedModule->GetStringPoolString(callResult.mValue, mContext->mUnreifiedModule->mBfIRBuilder);
if (stringPtr != NULL)
return *stringPtr;
}
return "";
}
void BfCompiler::HandleGeneratorErrors(StringImpl& result)
{
if ((mPassInstance->mErrors.IsEmpty()) && (mPassInstance->mOutStream.IsEmpty()))
return;
result.Clear();
for (auto& msg : mPassInstance->mOutStream)
{
String error = msg;
error.Replace('\n', '\r');
result += "!error\t";
result += error;
result += "\n";
}
}
String BfCompiler::GetGeneratorTypeDefList()
{
String result;
BfProject* curProject = NULL;
Dictionary<BfProject*, int> projectIds;
BfResolvePassData resolvePassData;
SetAndRestoreValue<BfResolvePassData*> prevResolvePassData(mResolvePassData, &resolvePassData);
BfPassInstance passInstance(mSystem);
SetAndRestoreValue<BfPassInstance*> prevPassInstance(mPassInstance, &passInstance);
for (auto typeDef : mSystem->mTypeDefs)
{
if (typeDef->mProject->mDisabled)
continue;
if (typeDef->mIsPartial)
continue;
auto type = mContext->mUnreifiedModule->ResolveTypeDef(typeDef, BfPopulateType_BaseType);
if ((type != NULL) && (type->IsTypeInstance()))
{
auto typeInst = type->ToTypeInstance();
if ((typeInst->mBaseType != NULL) && (typeInst->mBaseType->IsInstanceOf(mCompilerGeneratorTypeDef)))
{
result += typeDef->mProject->mName;
result += ":";
result += BfTypeUtils::TypeToString(typeDef, BfTypeNameFlag_InternalName);
String nameString = GetGeneratorString(typeDef, typeInst, "GetName", NULL);
if (!nameString.IsEmpty())
result += "\t" + nameString;
result += "\n";
}
}
}
HandleGeneratorErrors(result);
return result;
}
String BfCompiler::GetGeneratorInitData(const StringImpl& typeName, const StringImpl& args)
{
BfResolvePassData resolvePassData;
SetAndRestoreValue<BfResolvePassData*> prevResolvePassData(mResolvePassData, &resolvePassData);
BfPassInstance passInstance(mSystem);
SetAndRestoreValue<BfPassInstance*> prevPassInstance(mPassInstance, &passInstance);
Array<BfTypeDef*> typeDefs;
GetTypeDefs(typeName, typeDefs);
String result;
for (auto typeDef : typeDefs)
{
result += GetGeneratorString(typeDef, NULL, "InitUI", &args);
if (!result.IsEmpty())
break;
}
HandleGeneratorErrors(result);
return result;
}
String BfCompiler::GetGeneratorGenData(const StringImpl& typeName, const StringImpl& args)
{
BfResolvePassData resolvePassData;
SetAndRestoreValue<BfResolvePassData*> prevResolvePassData(mResolvePassData, &resolvePassData);
BfPassInstance passInstance(mSystem);
SetAndRestoreValue<BfPassInstance*> prevPassInstance(mPassInstance, &passInstance);
Array<BfTypeDef*> typeDefs;
GetTypeDefs(typeName, typeDefs);
String result;
for (auto typeDef : typeDefs)
{
result += GetGeneratorString(typeDef, NULL, "Generate", &args);
if (!result.IsEmpty())
break;
}
HandleGeneratorErrors(result);
return result;
}
struct TypeDefMatchHelper
{
public:
@ -8580,9 +8725,9 @@ String BfCompiler::GetTypeDefMatches(const StringImpl& searchStr)
return result;
}
String BfCompiler::GetTypeDefInfo(const StringImpl& inTypeName)
void BfCompiler::GetTypeDefs(const StringImpl& inTypeName, Array<BfTypeDef*>& typeDefs)
{
BfProject* project = NULL;
BfProject* project = NULL;
int idx = 0;
int sep = (int)inTypeName.IndexOf(':');
@ -8595,7 +8740,7 @@ String BfCompiler::GetTypeDefInfo(const StringImpl& inTypeName)
String typeName;
int genericCount = 0;
int pendingGenericCount = 0;
for ( ; idx < (int)inTypeName.length(); idx++)
for (; idx < (int)inTypeName.length(); idx++)
{
char c = inTypeName[idx];
if (c == '<')
@ -8606,7 +8751,7 @@ String BfCompiler::GetTypeDefInfo(const StringImpl& inTypeName)
genericCount++;
else if (c == '>')
{
pendingGenericCount = genericCount;
pendingGenericCount = genericCount;
genericCount = 0;
}
}
@ -8620,10 +8765,10 @@ String BfCompiler::GetTypeDefInfo(const StringImpl& inTypeName)
typeName += c;
}
}
bool isGlobals = false;
if (typeName == ":static")
{
{
typeName.clear();
isGlobals = true;
}
@ -8637,63 +8782,73 @@ String BfCompiler::GetTypeDefInfo(const StringImpl& inTypeName)
if (typeName[i] == '+')
typeName[i] = '.';
String result;
TypeDefMatchHelper matchHelper(result);
BfAtomComposite nameComposite;
BfAtomComposite nameComposite;
if ((typeName.IsEmpty()) || (mSystem->ParseAtomComposite(typeName, nameComposite)))
{
{
auto itr = mSystem->mTypeDefs.TryGet(nameComposite);
while (itr)
{
{
auto typeDef = *itr;
if ((!typeDef->mIsPartial) &&
(typeDef->mProject == project) &&
(typeDef->mFullName == nameComposite) &&
(typeDef->IsGlobalsContainer() == isGlobals) &&
(typeDef->GetSelfGenericParamCount() == pendingGenericCount))
{
auto refNode = typeDef->GetRefNode();
result += "S";
matchHelper.AddLocation(refNode);
result += "\n";
for (auto fieldDef : typeDef->mFields)
{
result += "F";
result += fieldDef->mName;
matchHelper.AddFieldDef(fieldDef);
}
for (auto propDef : typeDef->mProperties)
{
if (propDef->GetRefNode() == NULL)
continue;
result += "P";
matchHelper.AddPropertyDef(typeDef, propDef);
}
for (auto methodDef : typeDef->mMethods)
{
if ((methodDef->mMethodType != BfMethodType_Normal) &&
(methodDef->mMethodType != BfMethodType_Mixin) &&
(methodDef->mMethodType != BfMethodType_Ctor) &&
(methodDef->mMethodType != BfMethodType_Dtor))
continue;
if (methodDef->mMethodDeclaration == NULL)
continue;
result += "M";
matchHelper.AddMethodDef(methodDef);
}
{
typeDefs.Add(typeDef);
}
itr.MoveToNextHashMatch();
}
}
}
String BfCompiler::GetTypeDefInfo(const StringImpl& inTypeName)
{
Array<BfTypeDef*> typeDefs;
GetTypeDefs(inTypeName, typeDefs);
String result;
TypeDefMatchHelper matchHelper(result);
for (auto typeDef : typeDefs)
{
auto refNode = typeDef->GetRefNode();
result += "S";
matchHelper.AddLocation(refNode);
result += "\n";
for (auto fieldDef : typeDef->mFields)
{
result += "F";
result += fieldDef->mName;
matchHelper.AddFieldDef(fieldDef);
}
for (auto propDef : typeDef->mProperties)
{
if (propDef->GetRefNode() == NULL)
continue;
result += "P";
matchHelper.AddPropertyDef(typeDef, propDef);
}
for (auto methodDef : typeDef->mMethods)
{
if ((methodDef->mMethodType != BfMethodType_Normal) &&
(methodDef->mMethodType != BfMethodType_Mixin) &&
(methodDef->mMethodType != BfMethodType_Ctor) &&
(methodDef->mMethodType != BfMethodType_Dtor))
continue;
if (methodDef->mMethodDeclaration == NULL)
continue;
result += "M";
matchHelper.AddMethodDef(methodDef);
}
}
return result;
}
@ -8970,6 +9125,30 @@ BF_EXPORT void BF_CALLTYPE BfCompiler_ProgramDone()
#endif
}
BF_EXPORT const char* BF_CALLTYPE BfCompiler_GetGeneratorTypeDefList(BfCompiler* bfCompiler)
{
String& outString = *gTLStrReturn.Get();
outString.clear();
outString = bfCompiler->GetGeneratorTypeDefList();
return outString.c_str();
}
BF_EXPORT const char* BF_CALLTYPE BfCompiler_GetGeneratorInitData(BfCompiler* bfCompiler, char* typeDefName, char* args)
{
String& outString = *gTLStrReturn.Get();
outString.clear();
outString = bfCompiler->GetGeneratorInitData(typeDefName, args);
return outString.c_str();
}
BF_EXPORT const char* BF_CALLTYPE BfCompiler_GetGeneratorGenData(BfCompiler* bfCompiler, char* typeDefName, char* args)
{
String& outString = *gTLStrReturn.Get();
outString.clear();
outString = bfCompiler->GetGeneratorGenData(typeDefName, args);
return outString.c_str();
}
BF_EXPORT const char* BF_CALLTYPE BfCompiler_GetTypeDefList(BfCompiler* bfCompiler)
{
String& outString = *gTLStrReturn.Get();

View file

@ -374,6 +374,7 @@ public:
BfTypeDef* mInternalTypeDef;
BfTypeDef* mPlatformTypeDef;
BfTypeDef* mCompilerTypeDef;
BfTypeDef* mCompilerGeneratorTypeDef;
BfTypeDef* mDiagnosticsDebugTypeDef;
BfTypeDef* mIDisposableTypeDef;
BfTypeDef* mIIntegerTypeDef;
@ -511,9 +512,15 @@ public:
void ProcessAutocompleteTempType();
void GetSymbolReferences();
void Cancel();
void RequestFastFinish();
void RequestFastFinish();
String GetTypeDefList();
String GetTypeDefMatches(const StringImpl& searchSrc);
String GetGeneratorString(BfTypeDef* typeDef, BfTypeInstance* typeInst, const StringImpl& generatorMethodName, const StringImpl* args);
void HandleGeneratorErrors(StringImpl& result);
String GetGeneratorTypeDefList();
String GetGeneratorInitData(const StringImpl& typeName, const StringImpl& args);
String GetGeneratorGenData(const StringImpl& typeName, const StringImpl& args);
String GetTypeDefMatches(const StringImpl& searchSrc);
void GetTypeDefs(const StringImpl& typeName, Array<BfTypeDef*>& typeDefs);
String GetTypeDefInfo(const StringImpl& typeName);
int GetEmitSource(const StringImpl& fileName, StringImpl* outBuffer);

View file

@ -11789,7 +11789,7 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr)
if (mExpectingType->IsFunction())
{
BfIRValue result;
if ((hasIncompatibleCallingConventions) && (mModule->HasCompiledOutput()))
if ((hasIncompatibleCallingConventions) && (mModule->HasExecutedOutput()))
{
//
{
@ -11949,7 +11949,7 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr)
// Do we need a special delegate type for this?
if (((captureThisByValue) || (needsSplat) || (implicitParamCount > 0) /*|| (hasIncompatibleCallingConventions)*/) &&
(mModule->HasCompiledOutput()))
(mModule->HasExecutedOutput()))
{
hasCaptures = true;
auto curProject = mModule->mCurTypeInstance->mTypeDef->mProject;
@ -12030,7 +12030,7 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr)
// Do we need specialized calling code for this?
BfIRValue funcValue;
if (((needsSplat) || (implicitParamCount > 0) || (hasIncompatibleCallingConventions)) &&
(mModule->HasCompiledOutput()))
(mModule->HasExecutedOutput()))
{
int fieldIdx = 0;
for (int implicitParamIdx = bindMethodInstance->HasThis() ? -1 : 0; implicitParamIdx < implicitParamCount; implicitParamIdx++)
@ -12208,7 +12208,7 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr)
// >> delegate.mTarget = bindResult.mTarget
BfIRValue valPtr;
if (mModule->HasCompiledOutput())
if (mModule->HasExecutedOutput())
{
if ((implicitParamCount > 0) || (needsSplat)) // Point back to self, it contains capture data
valPtr = mModule->mBfIRBuilder->CreateBitCast(mResult.mValue, mModule->mBfIRBuilder->GetPrimitiveType(BfTypeCode_NullPtr));
@ -12226,7 +12226,7 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr)
if (!funcValue)
{
if ((mModule->HasCompiledOutput()) && (!mModule->mBfIRBuilder->mIgnoreWrites))
if ((mModule->HasExecutedOutput()) && (!mModule->mBfIRBuilder->mIgnoreWrites))
mModule->AssertErrorState();
return;
}
@ -13188,7 +13188,7 @@ BfLambdaInstance* BfExprEvaluator::GetLambdaInstance(BfLambdaBindExpression* lam
mModule->mIncompleteMethodCount++;
SetAndRestoreValue<BfClosureState*> prevClosureState(mModule->mCurMethodState->mClosureState, &closureState);
if (mModule->HasCompiledOutput())
if (mModule->HasExecutedOutput())
mModule->SetupIRMethod(methodInstance, methodInstance->mIRFunction, methodInstance->mAlwaysInline);
// This keeps us from giving errors twice. ProcessMethod can give errors when we capture by value but needed to
@ -14415,7 +14415,7 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs
{
if (!bindResult.mFunc)
{
BF_ASSERT((!mModule->HasCompiledOutput()) || (mModule->mBfIRBuilder->mIgnoreWrites));
BF_ASSERT((!mModule->HasExecutedOutput()) || (mModule->mBfIRBuilder->mIgnoreWrites));
appendSizeValue = mModule->GetConstValue(0);
}
else
@ -19717,7 +19717,7 @@ void BfExprEvaluator::Visit(BfIndexerExpression* indexerExpr)
}
}
}
else if (((mModule->HasCompiledOutput()) || (mModule->mIsComptimeModule)) &&
else if (((mModule->HasExecutedOutput()) || (mModule->mIsComptimeModule)) &&
(wantsChecks))
{
if (checkedKind == BfCheckedKind_NotSet)

View file

@ -9617,6 +9617,11 @@ bool BfModule::HasCompiledOutput()
return (!mSystem->mIsResolveOnly) && (mGeneratesCode) && (!mIsComptimeModule);
}
bool BfModule::HasExecutedOutput()
{
return ((!mSystem->mIsResolveOnly) && (mGeneratesCode)) || (mIsComptimeModule);
}
// We will skip the object access check for any occurrences of this value
void BfModule::SkipObjectAccessCheck(BfTypedValue typedVal)
{
@ -15818,7 +15823,7 @@ void BfModule::CreateStaticCtor()
auto methodDef = mCurMethodInstance->mMethodDef;
BfIRBlock exitBB;
if ((HasCompiledOutput()) && (!mCurMethodInstance->mIsUnspecialized) && (mCurMethodInstance->mChainType != BfMethodChainType_ChainMember))
if ((HasExecutedOutput()) && (!mCurMethodInstance->mIsUnspecialized) && (mCurMethodInstance->mChainType != BfMethodChainType_ChainMember))
{
auto boolType = GetPrimitiveType(BfTypeCode_Boolean);
auto didStaticInitVarAddr = mBfIRBuilder->CreateGlobalVariable(
@ -17041,7 +17046,7 @@ void BfModule::EmitCtorBody(bool& skipBody)
break;
}
if ((HasCompiledOutput()) && (matchedMethod != NULL))
if ((HasExecutedOutput()) && (matchedMethod != NULL))
{
SizedArray<BfIRValue, 1> args;
auto ctorBodyMethodInstance = GetMethodInstance(mCurTypeInstance->mBaseType, matchedMethod, BfTypeVector());
@ -18486,7 +18491,7 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
return;
}
if (HasCompiledOutput())
if (HasExecutedOutput())
{
BF_ASSERT(mIsModuleMutable);
}
@ -19713,7 +19718,7 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
skipBody = true;
skipEndChecks = true;
if ((HasCompiledOutput()) || (mIsComptimeModule))
if (HasExecutedOutput())
{
// Clear out DebugLoc - to mark the ".addr" code as part of prologue
mBfIRBuilder->ClearDebugLocation();
@ -19977,7 +19982,7 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
else if ((mCurTypeInstance->IsEnum()) && (!mCurTypeInstance->IsBoxed()) && (methodDef->mName == BF_METHODNAME_TO_STRING))
{
auto enumType = ResolveTypeDef(mCompiler->mEnumTypeDef);
if ((HasCompiledOutput()) || (mIsComptimeModule))
if (HasExecutedOutput())
{
EmitEnumToStringBody();
}
@ -19990,7 +19995,7 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
else if ((mCurTypeInstance->IsTuple()) && (!mCurTypeInstance->IsBoxed()) && (methodDef->mName == BF_METHODNAME_TO_STRING))
{
auto enumType = ResolveTypeDef(mCompiler->mEnumTypeDef);
if ((HasCompiledOutput()) || (mIsComptimeModule))
if (HasExecutedOutput())
{
EmitTupleToStringBody();
}
@ -20032,7 +20037,7 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
{
mBfIRBuilder->CreateRetVoid();
}
else if ((HasCompiledOutput()) || (mIsComptimeModule))
else if (HasExecutedOutput())
{
String autoPropName = typeDef->GetAutoPropertyName(propertyDeclaration);
BfFieldInstance* fieldInstance = GetFieldByName(mCurTypeInstance, autoPropName);

View file

@ -1633,6 +1633,7 @@ public:
bool IsTargetingBeefBackend();
bool WantsLifetimes();
bool HasCompiledOutput();
bool HasExecutedOutput();
void SkipObjectAccessCheck(BfTypedValue typedVal);
void EmitObjectAccessCheck(BfTypedValue typedVal);
void EmitEnsureInstructionAt();

View file

@ -1288,7 +1288,7 @@ void CeBuilder::Build()
auto methodInstance = mCeFunction->mMethodInstance;
if (methodInstance != NULL)
{
{
BfMethodInstance dupMethodInstance;
dupMethodInstance.CopyFrom(methodInstance);
auto methodDef = methodInstance->mMethodDef;
@ -1638,10 +1638,10 @@ void CeBuilder::Build()
EmitBinaryOp(CeOp_Shl_I8, CeOp_InvalidOp, ceLHS, ceRHS, result);
break;
case BeBinaryOpKind_RightShift:
EmitBinaryOp(CeOp_Shr_I8, CeOp_InvalidOp, ceLHS, ceRHS, result);
EmitBinaryOp(CeOp_Shr_U8, CeOp_InvalidOp, ceLHS, ceRHS, result);
break;
case BeBinaryOpKind_ARightShift:
EmitBinaryOp(CeOp_Shr_U8, CeOp_InvalidOp, ceLHS, ceRHS, result);
EmitBinaryOp(CeOp_Shr_I8, CeOp_InvalidOp, ceLHS, ceRHS, result);
break;
default:
Fail("Invalid binary op");
@ -2476,7 +2476,18 @@ void CeBuilder::Build()
EmitFrameOffset(ceSize);
}
break;
case BfIRIntrinsic_MemSet:
{
CeOperand ceDestPtr = GetOperand(castedInst->mArgs[0].mValue);
CeOperand ceValue = GetOperand(castedInst->mArgs[1].mValue);
CeOperand ceSize = GetOperand(castedInst->mArgs[2].mValue);
Emit(CeOp_MemSet);
EmitFrameOffset(ceDestPtr);
EmitFrameOffset(ceValue);
EmitFrameOffset(ceSize);
}
break;
case BfIRIntrinsic_AtomicFence:
// Nothing to do