From 98da39a3ba019ee6e5a1a7cb2c82e20a3ef18c56 Mon Sep 17 00:00:00 2001 From: EinBurgbauer Date: Tue, 13 Apr 2021 09:30:59 +0200 Subject: [PATCH 001/139] properly reset internal state on close --- BeefLibs/corlib/src/IO/BufferedStream.bf | 7 ++++++- BeefLibs/corlib/src/IO/FileStream.bf | 8 ++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/BeefLibs/corlib/src/IO/BufferedStream.bf b/BeefLibs/corlib/src/IO/BufferedStream.bf index 24c0afd4..8fc12e57 100644 --- a/BeefLibs/corlib/src/IO/BufferedStream.bf +++ b/BeefLibs/corlib/src/IO/BufferedStream.bf @@ -179,7 +179,12 @@ namespace System.IO public override Result Close() { - return Flush(); + let ret = Flush(); + + mPos = 0; + mBufferPos = -Int32.MinValue; + mBufferEnd = -Int32.MinValue; + return ret; } } } diff --git a/BeefLibs/corlib/src/IO/FileStream.bf b/BeefLibs/corlib/src/IO/FileStream.bf index 6ffd0e44..c193b610 100644 --- a/BeefLibs/corlib/src/IO/FileStream.bf +++ b/BeefLibs/corlib/src/IO/FileStream.bf @@ -371,14 +371,14 @@ namespace System.IO public override Result Close() { - var hadError = Flush() case .Err; + let ret = base.Close(); if (mBfpFile != null) Platform.BfpFile_Release(mBfpFile); + mBfpFile = null; mFileAccess = default; - if (hadError) - return .Err; - return .Ok; + mBfpFilePos = 0; + return ret; } protected override void UpdateLength() From 694e6636309ec121c1481fe2497b171f46e2f897 Mon Sep 17 00:00:00 2001 From: disarray2077 <86157825+disarray2077@users.noreply.github.com> Date: Mon, 2 Aug 2021 23:38:54 -0300 Subject: [PATCH 002/139] Add support for Vista File Dialogs --- BeefLibs/corlib/src/IO/FileDialog.Vista.bf | 159 ++++++ BeefLibs/corlib/src/IO/FileDialog.bf | 456 +++++++++++++++ BeefLibs/corlib/src/IO/FolderBrowserDialog.bf | 149 +---- BeefLibs/corlib/src/IO/OpenFileDialog.bf | 518 +++--------------- BeefLibs/corlib/src/IO/SaveFileDialog.bf | 41 ++ BeefLibs/corlib/src/Windows.bf | 209 +++++++ 6 files changed, 935 insertions(+), 597 deletions(-) create mode 100644 BeefLibs/corlib/src/IO/FileDialog.Vista.bf create mode 100644 BeefLibs/corlib/src/IO/FileDialog.bf diff --git a/BeefLibs/corlib/src/IO/FileDialog.Vista.bf b/BeefLibs/corlib/src/IO/FileDialog.Vista.bf new file mode 100644 index 00000000..994a2382 --- /dev/null +++ b/BeefLibs/corlib/src/IO/FileDialog.Vista.bf @@ -0,0 +1,159 @@ +// This file contains portions of code released by Microsoft under the MIT license as part +// of an open-sourcing initiative in 2014 of the C# core libraries. +// The original source was submitted to https://github.com/Microsoft/referencesource + +using System.Diagnostics; +using System.Collections; + +#if BF_PLATFORM_WINDOWS +namespace System.IO +{ + extension FileDialog + { + protected abstract Result CreateVistaDialog(); + + private Result TryRunDialogVista(Windows.HWnd hWndOwner) + { + Windows.COM_IFileDialog* dialog; + if (!(CreateVistaDialog() case .Ok(out dialog))) + return .Err; + + OnBeforeVistaDialog(dialog); + dialog.VT.Show(dialog, hWndOwner); + + List files = scope .(); + ProcessVistaFiles(dialog, files); + + DeleteContainerAndItems!(mFileNames); + mFileNames = new String[files.Count]; + files.CopyTo(mFileNames); + + dialog.VT.Release(dialog); + + return .Ok(files.IsEmpty ? .Cancel : .OK); + } + + private void OnBeforeVistaDialog(Windows.COM_IFileDialog* dialog) + { + dialog.VT.SetDefaultExtension(dialog, DefaultExt.ToScopedNativeWChar!()); + + if (mFileNames != null && !mFileNames.IsEmpty) + dialog.VT.SetFileName(dialog, mFileNames[0].ToScopedNativeWChar!()); + + if (!String.IsNullOrEmpty(mInitialDir)) + { + Windows.COM_IShellItem* folderShellItem = null; + Windows.SHCreateItemFromParsingName(mInitialDir.ToScopedNativeWChar!(), null, Windows.COM_IShellItem.sIID, (void**)&folderShellItem); + if (folderShellItem != null) + { + dialog.VT.SetDefaultFolder(dialog, folderShellItem); + dialog.VT.SetFolder(dialog, folderShellItem); + folderShellItem.VT.Release(folderShellItem); + } + } + + dialog.VT.SetTitle(dialog, mTitle.ToScopedNativeWChar!()); + dialog.VT.SetOptions(dialog, GetOptions()); + SetFileTypes(dialog); + } + + private Windows.COM_IFileDialog.FOS GetOptions() + { + const Windows.COM_IFileDialog.FOS BlittableOptions = + Windows.COM_IFileDialog.FOS.OVERWRITEPROMPT + | Windows.COM_IFileDialog.FOS.NOCHANGEDIR + | Windows.COM_IFileDialog.FOS.NOVALIDATE + | Windows.COM_IFileDialog.FOS.ALLOWMULTISELECT + | Windows.COM_IFileDialog.FOS.PATHMUSTEXIST + | Windows.COM_IFileDialog.FOS.FILEMUSTEXIST + | Windows.COM_IFileDialog.FOS.CREATEPROMPT + | Windows.COM_IFileDialog.FOS.NODEREFERENCELINKS; + + const int32 UnexpectedOptions = + (int32)(Windows.OFN_SHOWHELP // If ShowHelp is true, we don't use the Vista Dialog + | Windows.OFN_ENABLEHOOK // These shouldn't be set in options (only set in the flags for the legacy dialog) + | Windows.OFN_ENABLESIZING // These shouldn't be set in options (only set in the flags for the legacy dialog) + | Windows.OFN_EXPLORER); // These shouldn't be set in options (only set in the flags for the legacy dialog) + + Debug.Assert((UnexpectedOptions & mOptions) == 0, "Unexpected FileDialog options"); + + Windows.COM_IFileDialog.FOS ret = (Windows.COM_IFileDialog.FOS)mOptions & BlittableOptions; + + // Force no mini mode for the SaveFileDialog + ret |= Windows.COM_IFileDialog.FOS.DEFAULTNOMINIMODE; + + // Make sure that the Open dialog allows the user to specify + // non-file system locations. This flag will cause the dialog to copy the resource + // to a local cache (Temporary Internet Files), and return that path instead. This + // also affects the Save dialog by disallowing navigation to these areas. + // An example of a non-file system location is a URL (http://), or a file stored on + // a digital camera that is not mapped to a drive letter. + // This reproduces the behavior of the "classic" Open and Save dialogs. + ret |= Windows.COM_IFileDialog.FOS.FORCEFILESYSTEM; + + return ret; + } + + protected abstract void ProcessVistaFiles(Windows.COM_IFileDialog* dialog, List files); + + private Result SetFileTypes(Windows.COM_IFileDialog* dialog) + { + List filterItems = scope .(); + GetFilterItems(filterItems, mFilter); + + if (filterItems.Count == 0) + return .Ok; + + defer + { + for (var filter in filterItems) + { + delete filter.pszName; + delete filter.pszSpec; + } + } + + Windows.COM_IUnknown.HResult hr = dialog.VT.SetFileTypes(dialog, (uint32)filterItems.Count, filterItems.Ptr); + if (hr.Failed) + return .Err; + + hr = dialog.VT.SetFileTypeIndex(dialog, (uint32)mFilterIndex); + if (hr.Failed) + return .Err; + + return .Ok; + } + + private static void GetFilterItems(List list, String filter) + { + mixin ToHeapWChar(var str) + { + int encodedLen = System.Text.UTF16.GetEncodedLen(str); + char16* buf = new char16[encodedLen]* ( ? ); + System.Text.UTF16.Encode(str, buf, encodedLen); + buf + } + + // Expected input types + // "Text files (*.txt)|*.txt|All files (*.*)|*.*" + // "Image Files(*.BMP;*.JPG;*.GIF)|*.BMP;*.JPG;*.GIF|All files (*.*)|*.*" + if (!String.IsNullOrEmpty(filter)) + { + StringView[] tokens = filter.Split!('|'); + if (0 == tokens.Count % 2) + { + // All even numbered tokens should be labels + // Odd numbered tokens are the associated extensions + for (int i = 1; i < tokens.Count; i += 2) + { + Windows.COMDLG_FILTERSPEC ext; + ext.pszSpec = ToHeapWChar!(tokens[i]); // This may be a semicolon delimited list of extensions (that's ok) + ext.pszName = ToHeapWChar!(tokens[i - 1]); + list.Add(ext); + } + } + } + } + } +} +#endif \ No newline at end of file diff --git a/BeefLibs/corlib/src/IO/FileDialog.bf b/BeefLibs/corlib/src/IO/FileDialog.bf new file mode 100644 index 00000000..0ca13890 --- /dev/null +++ b/BeefLibs/corlib/src/IO/FileDialog.bf @@ -0,0 +1,456 @@ +// This file contains portions of code released by Microsoft under the MIT license as part +// of an open-sourcing initiative in 2014 of the C# core libraries. +// The original source was submitted to https://github.com/Microsoft/referencesource + +using System.Text; +using System.Collections; +using System.Threading; +using System.Diagnostics; + +#if BF_PLATFORM_WINDOWS +namespace System.IO +{ + enum DialogResult + { + None = 0, + OK = 1, + Cancel = 2 + } + + abstract class CommonDialog + { + public Windows.HWnd mHWnd; + public Windows.HWnd mDefaultControlHwnd; + public int mDefWndProc; + + private const int32 CDM_SETDEFAULTFOCUS = Windows.WM_USER + 0x51; + + public static Dictionary sHookMap = new Dictionary() ~ + { + Debug.Assert(sHookMap.Count == 0); + delete _; + }; + public static Monitor sMonitor = new Monitor() ~ delete _; + + public Result ShowDialog(INativeWindow owner = null) + { + Windows.HWnd hwndOwner = 0; + if (owner != null) + hwndOwner = (.)owner.Handle; + //Native.WndProc wndProc = scope => OwnerWndProc; + + //mDefWndProc = Native.SetWindowLong(mHWnd, Native.GWL_WNDPROC, (intptr)wndProc.GetFuncPtr().Value); + + var result = RunDialog(hwndOwner); + return result; + } + + public virtual int OwnerWndProc(Windows.HWnd hWnd, int32 msg, int wParam, int lParam) + { + return Windows.CallWindowProcW(mDefWndProc, hWnd, msg, wParam, lParam); + } + + protected virtual int HookProc(Windows.HWnd hWnd, int32 msg, int wParam, int lparam) + { + if (msg == Windows.WM_INITDIALOG) + { + //TODO: MoveToScreenCenter(hWnd); + // Under some circumstances, the dialog + // does not initially focus on any control. We fix that by explicitly + // setting focus ourselves. See ASURT 39435. + // + mDefaultControlHwnd = (Windows.HWnd)wParam; + if (mDefaultControlHwnd != 0) + Windows.SetFocus(mDefaultControlHwnd); + } + else if (msg == Windows.WM_SETFOCUS) + { + Windows.PostMessageW(hWnd, CDM_SETDEFAULTFOCUS, 0, 0); + } + else if (msg == CDM_SETDEFAULTFOCUS) + { + // If the dialog box gets focus, bounce it to the default control. + // so we post a message back to ourselves to wait for the focus change then push it to the default + // control. See ASURT 84016. + // + if (mDefaultControlHwnd != 0) + Windows.SetFocus(mDefaultControlHwnd); + } + return 0; + } + + protected abstract Result RunDialog(Windows.HWnd hWndOwner); + } + + abstract class FileDialog : CommonDialog + { + protected abstract Result RunFileDialog(ref Windows.OpenFileName ofn); + + protected override Result RunDialog(Windows.HWnd hWndOwner) + { + if (TryRunDialogVista(hWndOwner) case .Ok(let result)) + return .Ok(result); + + return RunDialogOld(hWndOwner); + } + + private const int32 FILEBUFSIZE = 8192; + protected const int32 OPTION_ADDEXTENSION = (int32)0x80000000; + + protected int32 mOptions; + private String mTitle ~ delete _; + private String mInitialDir ~ delete _; + private String mDefaultExt ~ delete _; + protected String[] mFileNames ~ DeleteContainerAndItems!(_); + private bool mSecurityCheckFileNames; + private String mFilter ~ delete _; + private String mFilterBuffer = new String() ~ delete _; + private int32 mFilterIndex; + private bool mSupportMultiDottedExtensions; + private bool mIgnoreSecondFileOkNotification; // Used for VS Whidbey 95342 + private int32 mOKNotificationCount; // Same + //private String char8Buffer = new String(FILEBUFSIZE) ~ delete _; + + public this() + { + Reset(); + } + + public virtual void Reset() + { + DeleteAndNullify!(mTitle); + DeleteAndNullify!(mInitialDir); + DeleteAndNullify!(mDefaultExt); + DeleteContainerAndItems!(mFileNames); + mFileNames = null; + DeleteAndNullify!(mFilter); + mFilterIndex = 1; + mSupportMultiDottedExtensions = false; + mOptions = Windows.OFN_HIDEREADONLY | Windows.OFN_PATHMUSTEXIST | + OPTION_ADDEXTENSION; + } + + + + protected int32 Options + { + get + { + return mOptions & ( + Windows.OFN_READONLY | + Windows.OFN_HIDEREADONLY | + Windows.OFN_NOCHANGEDIR | + Windows.OFN_SHOWHELP | + Windows.OFN_NOVALIDATE | + Windows.OFN_ALLOWMULTISELECT | + Windows.OFN_PATHMUSTEXIST | + Windows.OFN_FILEMUSTEXIST | + Windows.OFN_NODEREFERENCELINKS | + Windows.OFN_OVERWRITEPROMPT); + //return mOptions; + } + } + + public StringView Title + { + set + { + String.NewOrSet!(mTitle, value); + } + + get + { + return mTitle; + } + } + + public StringView InitialDirectory + { + set + { + String.NewOrSet!(mInitialDir, value); + } + + get + { + return mInitialDir; + } + } + + public String[] FileNames + { + get + { + return mFileNames; + } + } + + public StringView FileName + { + set + { + if (mFileNames == null) + { + mFileNames = new String[](new String(value)); + } + } + } + + public bool AddExtension + { + get + { + return GetOption(OPTION_ADDEXTENSION); + } + + set + { + SetOption(OPTION_ADDEXTENSION, value); + } + } + + public virtual bool CheckFileExists + { + get + { + return GetOption(Windows.OFN_FILEMUSTEXIST); + } + + set + { + SetOption(Windows.OFN_FILEMUSTEXIST, value); + } + } + + public bool DereferenceLinks + { + get + { + return !GetOption(Windows.OFN_NODEREFERENCELINKS); + } + set + { + SetOption(Windows.OFN_NODEREFERENCELINKS, !value); + } + } + + public bool CheckPathExists + { + get + { + return GetOption(Windows.OFN_PATHMUSTEXIST); + } + + set + { + SetOption(Windows.OFN_PATHMUSTEXIST, value); + } + } + + public bool Multiselect + { + get + { + return GetOption(Windows.OFN_ALLOWMULTISELECT); + } + + set + { + SetOption(Windows.OFN_ALLOWMULTISELECT, value); + } + } + + public bool ValidateNames + { + get + { + return !GetOption(Windows.OFN_NOVALIDATE); + } + + set + { + SetOption(Windows.OFN_NOVALIDATE, !value); + } + } + + public StringView DefaultExt + { + get + { + return mDefaultExt == null ? "" : mDefaultExt; + } + + set + { + delete mDefaultExt; + mDefaultExt = null; + + //if (!String.IsNullOrEmpty(value)) + if (value.Length > 0) + { + mDefaultExt = new String(value); + if (mDefaultExt.StartsWith(".")) + mDefaultExt.Remove(0, 1); + } + } + } + + public void GetFilter(String outFilter) + { + if (mFilter != null) + outFilter.Append(mFilter); + } + + public Result SetFilter(StringView value) + { + String useValue = scope String(value); + if (useValue != null && useValue.Length > 0) + { + var formats = String.StackSplit!(useValue, '|'); + if (formats == null || formats.Count % 2 != 0) + { + return .Err; + } + /// + /*String[] formats = value.Split('|'); + if (formats == null || formats.Length % 2 != 0) + { + throw new ArgumentException(SR.GetString(SR.FileDialogInvalidFilter)); + }*/ + String.NewOrSet!(mFilter, useValue); + } + else + { + useValue = null; + DeleteAndNullify!(mFilter); + } + + return .Ok; + } + + protected bool GetOption(int32 option) + { + return (mOptions & option) != 0; + } + + protected void SetOption(int32 option, bool value) + { + if (value) + { + mOptions |= option; + } + else + { + mOptions &= ~option; + } + } + + private static Result MakeFilterString(String s, bool dereferenceLinks, String filterBuffer) + { + String useStr = s; + if (useStr == null || useStr.Length == 0) + { + // Workaround for Whidbey bug #5165 + // Apply the workaround only when DereferenceLinks is true and OS is at least WinXP. + if (dereferenceLinks && System.Environment.OSVersion.Version.Major >= 5) + { + useStr = " |*.*"; + } + else if (useStr == null) + { + return .Err; + } + } + + filterBuffer.Set(s); + for (int32 i = 0; i < filterBuffer.Length; i++) + if (filterBuffer[i] == '|') + filterBuffer[i] = (char8)0; + filterBuffer.Append((char8)0); + return .Ok; + } + + private Result RunDialogOld(Windows.HWnd hWndOwner) + { + //RunDialogTest(hWndOwner); + + Windows.WndProc hookProcPtr = => StaticHookProc; + Windows.OpenFileName ofn = Windows.OpenFileName(); + + char16[FILEBUFSIZE] char16Buffer = .(0, ?); + + if (mFileNames != null && !mFileNames.IsEmpty) + { + //int len = UTF16.GetEncodedLen(fileNames[0]); + //char16Buffer = scope:: char16[len + 1]*; + UTF16.Encode(mFileNames[0], (char16*)&char16Buffer, FILEBUFSIZE); + } + // Degrade to the older style dialog if we're not on Win2K. + // We do this by setting the struct size to a different value + // + + if (Environment.OSVersion.Platform != System.PlatformID.Win32NT || + Environment.OSVersion.Version.Major < 5) { + ofn.mStructSize = 0x4C; + } + ofn.mHwndOwner = hWndOwner; + ofn.mHInstance = (Windows.HInstance)Windows.GetModuleHandleW(null); + + if (mFilter != null) + { + Try!(MakeFilterString(mFilter, this.DereferenceLinks, mFilterBuffer)); + ofn.mFilter = mFilterBuffer.ToScopedNativeWChar!::(); + } + ofn.nFilterIndex = mFilterIndex; + ofn.mFile = (char16*)&char16Buffer; + ofn.nMaxFile = FILEBUFSIZE; + if (mInitialDir != null) + ofn.mInitialDir = mInitialDir.ToScopedNativeWChar!::(); + if (mTitle != null) + ofn.mTitle = mTitle.ToScopedNativeWChar!::(); + ofn.mFlags = Options | (Windows.OFN_EXPLORER | Windows.OFN_ENABLEHOOK | Windows.OFN_ENABLESIZING); + ofn.mHook = hookProcPtr; + ofn.mCustData = (int)Internal.UnsafeCastToPtr(this); + ofn.mFlagsEx = Windows.OFN_USESHELLITEM; + if (mDefaultExt != null && AddExtension) + ofn.mDefExt = mDefaultExt.ToScopedNativeWChar!::(); + + DeleteContainerAndItems!(mFileNames); + mFileNames = null; + //Security checks happen here + return RunFileDialog(ref ofn); + } + + static int StaticHookProc(Windows.HWnd hWnd, int32 msg, int wParam, int lparam) + { + if (msg == Windows.WM_INITDIALOG) + { + using (sMonitor.Enter()) + { + var ofn = (Windows.OpenFileName*)(void*)lparam; + sHookMap[(int)hWnd] = (CommonDialog)Internal.UnsafeCastToObject((void*)ofn.mCustData); + } + } + + CommonDialog dlg; + using (sMonitor.Enter()) + { + sHookMap.TryGetValue((int)hWnd, out dlg); + } + if (dlg == null) + return 0; + + dlg.[Friend]HookProc(hWnd, msg, wParam, lparam); + if (msg == Windows.WM_DESTROY) + { + using (sMonitor.Enter()) + { + sHookMap.Remove((int)hWnd); + } + } + return 0; + } + //TODO: Add ProcessFileNames for validation + } +} +#endif \ No newline at end of file diff --git a/BeefLibs/corlib/src/IO/FolderBrowserDialog.bf b/BeefLibs/corlib/src/IO/FolderBrowserDialog.bf index 91844228..420757ac 100644 --- a/BeefLibs/corlib/src/IO/FolderBrowserDialog.bf +++ b/BeefLibs/corlib/src/IO/FolderBrowserDialog.bf @@ -57,7 +57,7 @@ namespace System.IO ShowNewFolderButton = true; } - protected Result RunDialog_New(Windows.HWnd hWndOwner, FolderBrowserDialog.COM_IFileDialog* fileDialog) + protected Result RunDialog_New(Windows.HWnd hWndOwner, Windows.COM_IFileDialog* fileDialog) { //COM_IFileDialogEvents evts; /*COM_IFileDialogEvents.VTable funcs; @@ -106,8 +106,8 @@ namespace System.IO if (!mSelectedPath.IsEmpty) { - COM_IShellItem* folderShellItem = null; - Windows.SHCreateItemFromParsingName(mSelectedPath.ToScopedNativeWChar!(), null, COM_IShellItem.sIID, (void**)&folderShellItem); + Windows.COM_IShellItem* folderShellItem = null; + Windows.SHCreateItemFromParsingName(mSelectedPath.ToScopedNativeWChar!(), null, Windows.COM_IShellItem.sIID, (void**)&folderShellItem); if (folderShellItem != null) { fileDialog.VT.SetDefaultFolder(fileDialog, folderShellItem); @@ -121,7 +121,7 @@ namespace System.IO DialogResult result = .Cancel; mSelectedPath.Clear(); - COM_IShellItem* shellItem = null; + Windows.COM_IShellItem* shellItem = null; fileDialog.VT.GetResult(fileDialog, out shellItem); if (shellItem != null) { @@ -142,10 +142,10 @@ namespace System.IO protected override Result RunDialog(Windows.HWnd hWndOwner) { - FolderBrowserDialog.COM_IFileDialog* fileDialog = null; + Windows.COM_IFileDialog* fileDialog = null; Windows.COM_IUnknown.HResult hr; //if (mFolderKind == .Open) - hr = Windows.COM_IUnknown.CoCreateInstance(ref FolderBrowserDialog.COM_IFileDialog.sCLSID, null, .INPROC_SERVER, ref FolderBrowserDialog.COM_IFileDialog.sIID, (void**)&fileDialog); + hr = Windows.COM_IUnknown.CoCreateInstance(ref Windows.COM_IFileDialog.sCLSID, null, .INPROC_SERVER, ref Windows.COM_IFileDialog.sIID, (void**)&fileDialog); //else //hr = Windows.COM_IUnknown.CoCreateInstance(ref FolderBrowserDialog.COM_FileSaveDialog.sCLSID, null, .INPROC_SERVER, ref FolderBrowserDialog.COM_FileSaveDialog.sIID, (void**)&fileDialog); if (hr == 0) @@ -219,143 +219,6 @@ namespace System.IO } return 0; } - - struct FDE_SHAREVIOLATION_RESPONSE; - struct FDE_OVERWRITE_RESPONSE; - - struct COM_IFileDialogEvents : Windows.COM_IUnknown - { - public struct VTable : Windows.COM_IUnknown.VTable - { - public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog) OnFileOk; - public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog, COM_IShellItem* psiFolder) OnFolderChanging; - public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog) OnFolderChange; - public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog) OnSelectionChange; - public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog, FDE_SHAREVIOLATION_RESPONSE* pResponse) OnShareViolation; - public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog) OnTypeChange; - public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog, COM_IShellItem* shellItem, FDE_OVERWRITE_RESPONSE* response) OnOverwrite; - - } - } - - struct COM_IShellItem : Windows.COM_IUnknown - { - public static Guid sIID = .(0x43826d1e, 0xe718, 0x42ee, 0xbc, 0x55, 0xa1, 0xe2, 0x61, 0xc3, 0x7b, 0xfe); - - public enum SIGDN : uint32 - { - NORMALDISPLAY = 0x00000000, // SHGDN_NORMAL - PARENTRELATIVEPARSING = 0x80018001, // SHGDN_INFOLDER | SHGDN_FORPARSING - DESKTOPABSOLUTEPARSING = 0x80028000, // SHGDN_FORPARSING - PARENTRELATIVEEDITING = 0x80031001, // SHGDN_INFOLDER | SHGDN_FOREDITING - DESKTOPABSOLUTEEDITING = 0x8004c000, // SHGDN_FORPARSING | SHGDN_FORADDRESSBAR - FILESYSPATH = 0x80058000, // SHGDN_FORPARSING - URL = 0x80068000, // SHGDN_FORPARSING - PARENTRELATIVEFORADDRESSBAR = 0x8007c001, // SHGDN_INFOLDER | SHGDN_FORPARSING | SHGDN_FORADDRESSBAR - PARENTRELATIVE = 0x80080001 // SHGDN_INFOLDER - } - - public struct VTable : Windows.COM_IUnknown.VTable - { - public function HResult(COM_IShellItem* self, void* pbc, ref Guid bhid, ref Guid riid, void** ppv) BindToHandler; - public function HResult(COM_IShellItem* self, out COM_IShellItem* ppsi) GetParent; - public function HResult(COM_IShellItem* self, SIGDN sigdnName, out char16* ppszName) GetDisplayName; - public function HResult(COM_IShellItem* self, uint sfgaoMask, out uint psfgaoAttribs) GetAttributes; - public function HResult(COM_IShellItem* self, COM_IShellItem* psi, uint32 hint, out int32 piOrder) Compare; - - } - public new VTable* VT - { - get - { - return (.)mVT; - } - } - } - - struct COMDLG_FILTERSPEC - { - public char16* pszName; - public char16* pszSpec; - } - - enum FDAP : uint32 - { - FDAP_BOTTOM = 0x00000000, - FDAP_TOP = 0x00000001, - } - - public struct COM_IFileDialog : Windows.COM_IUnknown - { - public static Guid sIID = .(0x42f85136, 0xdb7e, 0x439c, 0x85, 0xf1, 0xe4, 0x07, 0x5d, 0x13, 0x5f, 0xc8); - public static Guid sCLSID = .(0xdc1c5a9c, 0xe88a, 0x4dde, 0xa5, 0xa1, 0x60, 0xf8, 0x2a, 0x20, 0xae, 0xf7); - - ///s - public enum FOS : uint32 - { - OVERWRITEPROMPT = 0x00000002, - STRICTFILETYPES = 0x00000004, - NOCHANGEDIR = 0x00000008, - PICKFOLDERS = 0x00000020, - FORCEFILESYSTEM = 0x00000040, - ALLNONSTORAGEITEMS = 0x00000080, - NOVALIDATE = 0x00000100, - ALLOWMULTISELECT = 0x00000200, - PATHMUSTEXIST = 0x00000800, - FILEMUSTEXIST = 0x00001000, - CREATEPROMPT = 0x00002000, - SHAREAWARE = 0x00004000, - NOREADONLYRETURN = 0x00008000, - NOTESTFILECREATE = 0x00010000, - HIDEMRUPLACES = 0x00020000, - HIDEPINNEDPLACES = 0x00040000, - NODEREFERENCELINKS = 0x00100000, - DONTADDTORECENT = 0x02000000, - FORCESHOWHIDDEN = 0x10000000, - DEFAULTNOMINIMODE = 0x20000000 - } - - public struct VTable : Windows.COM_IUnknown.VTable - { - public function HResult(COM_IFileDialog* self, Windows.HWnd parent) Show; - public function HResult(COM_IFileDialog* self, uint cFileTypes, COMDLG_FILTERSPEC* rgFilterSpec) SetFileTypes; - public function HResult(COM_IFileDialog* self, uint iFileType) SetFileTypeIndex; - public function HResult(COM_IFileDialog* self, out uint piFileType) GetFileTypeIndex; - public function HResult(COM_IFileDialog* self, COM_IFileDialogEvents* pfde, out uint pdwCookie) Advise; - public function HResult(COM_IFileDialog* self, uint dwCookie) Unadvise; - public function HResult(COM_IFileDialog* self, FOS fos) SetOptions; - public function HResult(COM_IFileDialog* self, out FOS pfos) GetOptions; - public function HResult(COM_IFileDialog* self, COM_IShellItem* psi) SetDefaultFolder; - public function HResult(COM_IFileDialog* self, COM_IShellItem* psi) SetFolder; - public function HResult(COM_IFileDialog* self, out COM_IShellItem* ppsi) GetFolder; - public function HResult(COM_IFileDialog* self, out COM_IShellItem* ppsi) GetCurrentSelection; - public function HResult(COM_IFileDialog* self, char16* pszName) SetFileName; - public function HResult(COM_IFileDialog* self, out char16* pszName) GetFileName; - public function HResult(COM_IFileDialog* self, char16* pszTitle) SetTitle; - public function HResult(COM_IFileDialog* self, char16* pszText) SetOkButtonLabel; - public function HResult(COM_IFileDialog* self, char16* pszLabel) SetFileNameLabel; - public function HResult(COM_IFileDialog* self, out COM_IShellItem* ppsi) GetResult; - public function HResult(COM_IFileDialog* self, COM_IShellItem* psi, FDAP fdap) AddPlace; - public function HResult(COM_IFileDialog* self, char16* pszDefaultExtension) SetDefaultExtension; - public function HResult(COM_IFileDialog* self, int hr) Close; - public function HResult(COM_IFileDialog* self, ref Guid guid) SetClientGuid; - public function HResult(COM_IFileDialog* self) ClearClientData; - public function HResult(COM_IFileDialog* self, void* pFilter) SetFilter; - } - public new VTable* VT - { - get - { - return (.)mVT; - } - } - } - - public struct COM_FileSaveDialog : COM_IFileDialog - { - public static new Guid sIID = .(0x84bccd23, 0x5fde, 0x4cdb, 0xae, 0xa4, 0xaf, 0x64, 0xb8, 0x3d, 0x78, 0xab); - public static new Guid sCLSID = .(0xC0B4E2F3, 0xBA21, 0x4773, 0x8D, 0xBA, 0x33, 0x5E, 0xC9, 0x46, 0xEB, 0x8B); - } } } #endif \ No newline at end of file diff --git a/BeefLibs/corlib/src/IO/OpenFileDialog.bf b/BeefLibs/corlib/src/IO/OpenFileDialog.bf index 3697c1c5..6523c097 100644 --- a/BeefLibs/corlib/src/IO/OpenFileDialog.bf +++ b/BeefLibs/corlib/src/IO/OpenFileDialog.bf @@ -11,460 +11,6 @@ using System.Text; namespace System.IO { - enum DialogResult - { - None = 0, - OK = 1, - Cancel = 2 - } - - abstract class CommonDialog - { - public Windows.HWnd mHWnd; - public Windows.HWnd mDefaultControlHwnd; - public int mDefWndProc; - - private const int32 CDM_SETDEFAULTFOCUS = Windows.WM_USER + 0x51; - - public static Dictionary sHookMap = new Dictionary() ~ - { - Debug.Assert(sHookMap.Count == 0); - delete _; - }; - public static Monitor sMonitor = new Monitor() ~ delete _; - - public Result ShowDialog(INativeWindow owner = null) - { - Windows.HWnd hwndOwner = 0; - if (owner != null) - hwndOwner = (.)owner.Handle; - //Native.WndProc wndProc = scope => OwnerWndProc; - - //mDefWndProc = Native.SetWindowLong(mHWnd, Native.GWL_WNDPROC, (intptr)wndProc.GetFuncPtr().Value); - - var result = RunDialog(hwndOwner); - return result; - } - - public virtual int OwnerWndProc(Windows.HWnd hWnd, int32 msg, int wParam, int lParam) - { - return Windows.CallWindowProcW(mDefWndProc, hWnd, msg, wParam, lParam); - } - - protected virtual int HookProc(Windows.HWnd hWnd, int32 msg, int wParam, int lparam) - { - if (msg == Windows.WM_INITDIALOG) - { - //TODO: MoveToScreenCenter(hWnd); - // Under some circumstances, the dialog - // does not initially focus on any control. We fix that by explicitly - // setting focus ourselves. See ASURT 39435. - // - mDefaultControlHwnd = (Windows.HWnd)wParam; - if (mDefaultControlHwnd != 0) - Windows.SetFocus(mDefaultControlHwnd); - } - else if (msg == Windows.WM_SETFOCUS) - { - Windows.PostMessageW(hWnd, CDM_SETDEFAULTFOCUS, 0, 0); - } - else if (msg == CDM_SETDEFAULTFOCUS) - { - // If the dialog box gets focus, bounce it to the default control. - // so we post a message back to ourselves to wait for the focus change then push it to the default - // control. See ASURT 84016. - // - if (mDefaultControlHwnd != 0) - Windows.SetFocus(mDefaultControlHwnd); - } - return 0; - } - - protected abstract Result RunDialog(Windows.HWnd hWndOwner); - } - - abstract class FileDialog : CommonDialog - { - protected abstract Result RunFileDialog(ref Windows.OpenFileName ofn); - - protected override Result RunDialog(Windows.HWnd hWndOwner) - { - return RunDialogOld(hWndOwner); - } - - private const int32 FILEBUFSIZE = 8192; - protected const int32 OPTION_ADDEXTENSION = (int32)0x80000000; - - protected int32 mOptions; - private String mTitle ~ delete _; - private String mInitialDir ~ delete _; - private String mDefaultExt ~ delete _; - protected String[] mFileNames ~ DeleteContainerAndItems!(_); - private bool mSecurityCheckFileNames; - private String mFilter ~ delete _; - private String mFilterBuffer = new String() ~ delete _; - private int32 mFilterIndex; - private bool mSupportMultiDottedExtensions; - private bool mIgnoreSecondFileOkNotification; // Used for VS Whidbey 95342 - private int32 mOKNotificationCount; // Same - //private String char8Buffer = new String(FILEBUFSIZE) ~ delete _; - - public this() - { - Reset(); - } - - public virtual void Reset() - { - DeleteAndNullify!(mTitle); - DeleteAndNullify!(mInitialDir); - DeleteAndNullify!(mDefaultExt); - DeleteContainerAndItems!(mFileNames); - mFileNames = null; - DeleteAndNullify!(mFilter); - mFilterIndex = 1; - mSupportMultiDottedExtensions = false; - mOptions = Windows.OFN_HIDEREADONLY | Windows.OFN_PATHMUSTEXIST | - OPTION_ADDEXTENSION; - } - - protected int32 Options - { - get - { - return mOptions & ( - Windows.OFN_READONLY | - Windows.OFN_HIDEREADONLY | - Windows.OFN_NOCHANGEDIR | - Windows.OFN_SHOWHELP | - Windows.OFN_NOVALIDATE | - Windows.OFN_ALLOWMULTISELECT | - Windows.OFN_PATHMUSTEXIST | - Windows.OFN_FILEMUSTEXIST | - Windows.OFN_NODEREFERENCELINKS | - Windows.OFN_OVERWRITEPROMPT); - //return mOptions; - } - } - - public StringView Title - { - set - { - String.NewOrSet!(mTitle, value); - } - - get - { - return mTitle; - } - } - - public StringView InitialDirectory - { - set - { - String.NewOrSet!(mInitialDir, value); - } - - get - { - return mInitialDir; - } - } - - public String[] FileNames - { - get - { - return mFileNames; - } - } - - public StringView FileName - { - set - { - if (mFileNames == null) - { - mFileNames = new String[](new String(value)); - } - } - } - - public bool AddExtension - { - get - { - return GetOption(OPTION_ADDEXTENSION); - } - - set - { - SetOption(OPTION_ADDEXTENSION, value); - } - } - - public virtual bool CheckFileExists - { - get - { - return GetOption(Windows.OFN_FILEMUSTEXIST); - } - - set - { - SetOption(Windows.OFN_FILEMUSTEXIST, value); - } - } - - public bool DereferenceLinks - { - get - { - return !GetOption(Windows.OFN_NODEREFERENCELINKS); - } - set - { - SetOption(Windows.OFN_NODEREFERENCELINKS, !value); - } - } - - public bool CheckPathExists - { - get - { - return GetOption(Windows.OFN_PATHMUSTEXIST); - } - - set - { - SetOption(Windows.OFN_PATHMUSTEXIST, value); - } - } - - public bool Multiselect - { - get - { - return GetOption(Windows.OFN_ALLOWMULTISELECT); - } - - set - { - SetOption(Windows.OFN_ALLOWMULTISELECT, value); - } - } - - public bool ValidateNames - { - get - { - return !GetOption(Windows.OFN_NOVALIDATE); - } - - set - { - SetOption(Windows.OFN_NOVALIDATE, !value); - } - } - - public StringView DefaultExt - { - get - { - return mDefaultExt == null ? "" : mDefaultExt; - } - - set - { - delete mDefaultExt; - mDefaultExt = null; - - //if (!String.IsNullOrEmpty(value)) - if (value.Length > 0) - { - mDefaultExt = new String(value); - if (mDefaultExt.StartsWith(".")) - mDefaultExt.Remove(0, 1); - } - } - } - - public void GetFilter(String outFilter) - { - if (mFilter != null) - outFilter.Append(mFilter); - } - - public Result SetFilter(StringView value) - { - String useValue = scope String(value); - if (useValue != null && useValue.Length > 0) - { - var formats = String.StackSplit!(useValue, '|'); - if (formats == null || formats.Count % 2 != 0) - { - return .Err; - } - /// - /*String[] formats = value.Split('|'); - if (formats == null || formats.Length % 2 != 0) - { - throw new ArgumentException(SR.GetString(SR.FileDialogInvalidFilter)); - }*/ - String.NewOrSet!(mFilter, useValue); - } - else - { - useValue = null; - DeleteAndNullify!(mFilter); - } - - return .Ok; - } - - protected bool GetOption(int32 option) - { - return (mOptions & option) != 0; - } - - protected void SetOption(int32 option, bool value) - { - if (value) - { - mOptions |= option; - } - else - { - mOptions &= ~option; - } - } - - private static Result MakeFilterString(String s, bool dereferenceLinks, String filterBuffer) - { - String useStr = s; - if (useStr == null || useStr.Length == 0) - { - // Workaround for Whidbey bug #5165 - // Apply the workaround only when DereferenceLinks is true and OS is at least WinXP. - if (dereferenceLinks && System.Environment.OSVersion.Version.Major >= 5) - { - useStr = " |*.*"; - } - else if (useStr == null) - { - return .Err; - } - } - - filterBuffer.Set(s); - for (int32 i = 0; i < filterBuffer.Length; i++) - if (filterBuffer[i] == '|') - filterBuffer[i] = (char8)0; - filterBuffer.Append((char8)0); - return .Ok; - } - - public static mixin Testie() - { - int a = 123; - char16* buf; - if (a == 0) - { - buf = null; - } - else - { - buf = new char16[123]* ( ? ); - defer:mixin delete buf; - } - buf - } - - private Result RunDialogOld(Windows.HWnd hWndOwner) - { - //RunDialogTest(hWndOwner); - - Windows.WndProc hookProcPtr = => StaticHookProc; - Windows.OpenFileName ofn = Windows.OpenFileName(); - - char16[FILEBUFSIZE] char16Buffer = .(0, ?); - - if (mFileNames != null) - { - //int len = UTF16.GetEncodedLen(fileNames[0]); - //char16Buffer = scope:: char16[len + 1]*; - UTF16.Encode(mFileNames[0], (char16*)&char16Buffer, FILEBUFSIZE); - } - // Degrade to the older style dialog if we're not on Win2K. - // We do this by setting the struct size to a different value - // - - if (Environment.OSVersion.Platform != System.PlatformID.Win32NT || - Environment.OSVersion.Version.Major < 5) { - ofn.mStructSize = 0x4C; - } - ofn.mHwndOwner = hWndOwner; - ofn.mHInstance = (Windows.HInstance)Windows.GetModuleHandleW(null); - - if (mFilter != null) - { - Try!(MakeFilterString(mFilter, this.DereferenceLinks, mFilterBuffer)); - ofn.mFilter = mFilterBuffer.ToScopedNativeWChar!::(); - } - ofn.nFilterIndex = mFilterIndex; - ofn.mFile = (char16*)&char16Buffer; - ofn.nMaxFile = FILEBUFSIZE; - if (mInitialDir != null) - ofn.mInitialDir = mInitialDir.ToScopedNativeWChar!::(); - if (mTitle != null) - ofn.mTitle = mTitle.ToScopedNativeWChar!::(); - ofn.mFlags = Options | (Windows.OFN_EXPLORER | Windows.OFN_ENABLEHOOK | Windows.OFN_ENABLESIZING); - ofn.mHook = hookProcPtr; - ofn.mCustData = (int)Internal.UnsafeCastToPtr(this); - ofn.mFlagsEx = Windows.OFN_USESHELLITEM; - if (mDefaultExt != null && AddExtension) - ofn.mDefExt = mDefaultExt.ToScopedNativeWChar!::(); - - DeleteContainerAndItems!(mFileNames); - mFileNames = null; - //Security checks happen here - return RunFileDialog(ref ofn); - } - - static int StaticHookProc(Windows.HWnd hWnd, int32 msg, int wParam, int lparam) - { - if (msg == Windows.WM_INITDIALOG) - { - using (sMonitor.Enter()) - { - var ofn = (Windows.OpenFileName*)(void*)lparam; - sHookMap[(int)hWnd] = (CommonDialog)Internal.UnsafeCastToObject((void*)ofn.mCustData); - } - } - - CommonDialog dlg; - using (sMonitor.Enter()) - { - sHookMap.TryGetValue((int)hWnd, out dlg); - } - if (dlg == null) - return 0; - - dlg.[Friend]HookProc(hWnd, msg, wParam, lparam); - if (msg == Windows.WM_DESTROY) - { - using (sMonitor.Enter()) - { - sHookMap.Remove((int)hWnd); - } - } - return 0; - } - //TODO: Add ProcessFileNames for validation - } - class OpenFileDialog : FileDialog { public override void Reset() @@ -557,6 +103,70 @@ namespace System.IO return DialogResult.OK; } + + protected override void ProcessVistaFiles(Windows.COM_IFileDialog* dialog, List files) + { + mixin GetFilePathFromShellItem(Windows.COM_IShellItem* shellItem) + { + String str = null; + if (shellItem.VT.GetDisplayName(shellItem, .FILESYSPATH, let cStr) == .OK) + { + str = new String()..Append(cStr); + Windows.COM_IUnknown.CoTaskMemFree(cStr); + } + str + } + + Windows.COM_IFileOpenDialog* openDialog = (.)dialog; + if (Multiselect) + { + openDialog.VT.GetResults(openDialog, let results); + + if (results != null) + { + results.VT.GetCount(results, let count); + for (uint32 i < count) + { + results.VT.GetItemAt(results, i, let item); + if (item != null) + { + let filePath = GetFilePathFromShellItem!(item); + if (filePath != null) + files.Add(filePath); + } + } + results.VT.Release(results); + } + } + else + { + openDialog.VT.GetResult(openDialog, let shellItem); + + if (shellItem != null) + { + let filePath = GetFilePathFromShellItem!(shellItem); + if (filePath != null) + files.Add(filePath); + shellItem.VT.Release(shellItem); + } + } + } + + protected override Result CreateVistaDialog() + { + Windows.COM_IFileDialog* fileDialog = null; + + Windows.COM_IUnknown.HResult hr = (Windows.COM_IUnknown.CoCreateInstance( + ref Windows.COM_IFileDialog.sCLSID, + null, + .INPROC_SERVER | .LOCAL_SERVER | .REMOTE_SERVER, + ref Windows.COM_IFileOpenDialog.sIID, + (void**)&fileDialog)); + if (hr.Failed) + return .Err; + + return fileDialog; + } } } diff --git a/BeefLibs/corlib/src/IO/SaveFileDialog.bf b/BeefLibs/corlib/src/IO/SaveFileDialog.bf index 89585e2d..19064fbc 100644 --- a/BeefLibs/corlib/src/IO/SaveFileDialog.bf +++ b/BeefLibs/corlib/src/IO/SaveFileDialog.bf @@ -94,6 +94,47 @@ namespace System.IO return DialogResult.OK; } + + protected override void ProcessVistaFiles(Windows.COM_IFileDialog* dialog, System.Collections.List files) + { + mixin GetFilePathFromShellItem(Windows.COM_IShellItem* shellItem) + { + String str = null; + if (shellItem.VT.GetDisplayName(shellItem, .FILESYSPATH, let cStr) == .OK) + { + str = new String()..Append(cStr); + Windows.COM_IUnknown.CoTaskMemFree(cStr); + } + str + } + + Windows.COM_IFileSaveDialog* saveDialog = (.)dialog; + saveDialog.VT.GetResult(saveDialog, let shellItem); + + if (shellItem != null) + { + let filePath = GetFilePathFromShellItem!(shellItem); + if (filePath != null) + files.Add(filePath); + shellItem.VT.Release(shellItem); + } + } + + protected override Result CreateVistaDialog() + { + Windows.COM_IFileDialog* fileDialog = null; + + Windows.COM_IUnknown.HResult hr = (Windows.COM_IUnknown.CoCreateInstance( + ref Windows.COM_IFileSaveDialog.sCLSID, + null, + .INPROC_SERVER | .LOCAL_SERVER | .REMOTE_SERVER, + ref Windows.COM_IFileSaveDialog.sIID, + (void**)&fileDialog)); + if (hr.Failed) + return .Err; + + return fileDialog; + } } } diff --git a/BeefLibs/corlib/src/Windows.bf b/BeefLibs/corlib/src/Windows.bf index e1d1848c..78be9cb8 100644 --- a/BeefLibs/corlib/src/Windows.bf +++ b/BeefLibs/corlib/src/Windows.bf @@ -1117,6 +1117,215 @@ namespace System TRUSTEE_W Trustee; } + struct COM_IFileDialogEvents : Windows.COM_IUnknown + { + struct FDE_SHAREVIOLATION_RESPONSE; + struct FDE_OVERWRITE_RESPONSE; + + public struct VTable : Windows.COM_IUnknown.VTable + { + public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog) OnFileOk; + public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog, COM_IShellItem* psiFolder) OnFolderChanging; + public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog) OnFolderChange; + public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog) OnSelectionChange; + public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog, FDE_SHAREVIOLATION_RESPONSE* pResponse) OnShareViolation; + public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog) OnTypeChange; + public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog, COM_IShellItem* shellItem, FDE_OVERWRITE_RESPONSE* response) OnOverwrite; + + } + } + + public struct COM_IShellItem : Windows.COM_IUnknown + { + public static Guid sIID = .(0x43826d1e, 0xe718, 0x42ee, 0xbc, 0x55, 0xa1, 0xe2, 0x61, 0xc3, 0x7b, 0xfe); + + public enum SIGDN : uint32 + { + NORMALDISPLAY = 0x00000000, // SHGDN_NORMAL + PARENTRELATIVEPARSING = 0x80018001, // SHGDN_INFOLDER | SHGDN_FORPARSING + DESKTOPABSOLUTEPARSING = 0x80028000, // SHGDN_FORPARSING + PARENTRELATIVEEDITING = 0x80031001, // SHGDN_INFOLDER | SHGDN_FOREDITING + DESKTOPABSOLUTEEDITING = 0x8004c000, // SHGDN_FORPARSING | SHGDN_FORADDRESSBAR + FILESYSPATH = 0x80058000, // SHGDN_FORPARSING + URL = 0x80068000, // SHGDN_FORPARSING + PARENTRELATIVEFORADDRESSBAR = 0x8007c001, // SHGDN_INFOLDER | SHGDN_FORPARSING | SHGDN_FORADDRESSBAR + PARENTRELATIVE = 0x80080001 // SHGDN_INFOLDER + } + + public struct VTable : Windows.COM_IUnknown.VTable + { + public function HResult(COM_IShellItem* self, void* pbc, ref Guid bhid, ref Guid riid, void** ppv) BindToHandler; + public function HResult(COM_IShellItem* self, out COM_IShellItem* ppsi) GetParent; + public function HResult(COM_IShellItem* self, SIGDN sigdnName, out char16* ppszName) GetDisplayName; + public function HResult(COM_IShellItem* self, uint sfgaoMask, out uint psfgaoAttribs) GetAttributes; + public function HResult(COM_IShellItem* self, COM_IShellItem* psi, uint32 hint, out int32 piOrder) Compare; + + } + public new VTable* VT + { + get + { + return (.)mVT; + } + } + } + + public struct COM_IShellItemArray : Windows.COM_IUnknown + { + public enum GETPROPERTYSTOREFLAGS : uint + { + DEFAULT = 0x00000000, + HANDLERPROPERTIESONLY = 0x00000001, + READWRITE = 0x00000002, + TEMPORARY = 0x00000004, + FASTPROPERTIESONLY = 0x00000008, + OPENSLOWITEM = 0x00000010, + DELAYCREATION = 0x00000020, + BESTEFFORT = 0x00000040, + NO_OPLOCK = 0x00000080, + PREFERQUERYPROPERTIES = 0x00000100, + EXTRINSICPROPERTIES = 0x00000200, + EXTRINSICPROPERTIESONLY = 0x00000400, + VOLATILEPROPERTIES = 0x00000800, + VOLATILEPROPERTIESONLY = 0x00001000, + MASK_VALID = 0x00001FFF + } + + [AllowDuplicates] + public enum SIATTRIBFLAGS : uint + { + AND = 0x1, + OR = 0x2, + APPCOMPAT = 0x3, + MASK = 0x3, + ALLITEMS = 0x4000 + } + + public struct PROPERTYKEY; + + public static Guid sIID = .(0xB63EA76D, 0x1F85, 0x456F, 0xA1, 0x9C, 0x48, 0x15, 0x9E, 0xFA, 0x85, 0x8B); + + public struct VTable : Windows.COM_IUnknown.VTable + { + public function HResult(COM_IShellItemArray* self, void* pbc, ref Guid rbhid, ref Guid riid, out void* ppvOut) BindToHandler; + public function HResult(COM_IShellItemArray* self, GETPROPERTYSTOREFLAGS flags, ref Guid riid, out void* ppv) GetPropertyStore; + public function HResult(COM_IShellItemArray* self, ref PROPERTYKEY keyType, ref Guid riid, out void* ppv) GetPropertyDescriptionList; + public function HResult(COM_IShellItemArray* self, SIATTRIBFLAGS dwAttribFlags, uint32 sfgaoMask, out uint32 psfgaoAttribs) GetAttributes; + public function HResult(COM_IShellItemArray* self, out uint32 pdwNumItems) GetCount; + public function HResult(COM_IShellItemArray* self, uint32 dwIndex, out COM_IShellItem* ppsi) GetItemAt; + public function HResult(COM_IShellItemArray* self, out void* ppenumShellItems) EnumItems; + } + public new VTable* VT + { + get + { + return (.)mVT; + } + } + } + + public struct COMDLG_FILTERSPEC + { + public char16* pszName; + public char16* pszSpec; + } + + enum FDAP : uint32 + { + FDAP_BOTTOM = 0x00000000, + FDAP_TOP = 0x00000001, + } + + public struct COM_IFileDialog : Windows.COM_IUnknown + { + public static Guid sIID = .(0x42f85136, 0xdb7e, 0x439c, 0x85, 0xf1, 0xe4, 0x07, 0x5d, 0x13, 0x5f, 0xc8); + public static Guid sCLSID = .(0xdc1c5a9c, 0xe88a, 0x4dde, 0xa5, 0xa1, 0x60, 0xf8, 0x2a, 0x20, 0xae, 0xf7); + + ///s + public enum FOS : uint32 + { + OVERWRITEPROMPT = 0x00000002, + STRICTFILETYPES = 0x00000004, + NOCHANGEDIR = 0x00000008, + PICKFOLDERS = 0x00000020, + FORCEFILESYSTEM = 0x00000040, + ALLNONSTORAGEITEMS = 0x00000080, + NOVALIDATE = 0x00000100, + ALLOWMULTISELECT = 0x00000200, + PATHMUSTEXIST = 0x00000800, + FILEMUSTEXIST = 0x00001000, + CREATEPROMPT = 0x00002000, + SHAREAWARE = 0x00004000, + NOREADONLYRETURN = 0x00008000, + NOTESTFILECREATE = 0x00010000, + HIDEMRUPLACES = 0x00020000, + HIDEPINNEDPLACES = 0x00040000, + NODEREFERENCELINKS = 0x00100000, + DONTADDTORECENT = 0x02000000, + FORCESHOWHIDDEN = 0x10000000, + DEFAULTNOMINIMODE = 0x20000000 + } + + public struct VTable : Windows.COM_IUnknown.VTable + { + public function HResult(COM_IFileDialog* self, Windows.HWnd parent) Show; + public function HResult(COM_IFileDialog* self, uint cFileTypes, COMDLG_FILTERSPEC* rgFilterSpec) SetFileTypes; + public function HResult(COM_IFileDialog* self, uint iFileType) SetFileTypeIndex; + public function HResult(COM_IFileDialog* self, out uint piFileType) GetFileTypeIndex; + public function HResult(COM_IFileDialog* self, COM_IFileDialogEvents* pfde, out uint pdwCookie) Advise; + public function HResult(COM_IFileDialog* self, uint dwCookie) Unadvise; + public function HResult(COM_IFileDialog* self, FOS fos) SetOptions; + public function HResult(COM_IFileDialog* self, out FOS pfos) GetOptions; + public function HResult(COM_IFileDialog* self, COM_IShellItem* psi) SetDefaultFolder; + public function HResult(COM_IFileDialog* self, COM_IShellItem* psi) SetFolder; + public function HResult(COM_IFileDialog* self, out COM_IShellItem* ppsi) GetFolder; + public function HResult(COM_IFileDialog* self, out COM_IShellItem* ppsi) GetCurrentSelection; + public function HResult(COM_IFileDialog* self, char16* pszName) SetFileName; + public function HResult(COM_IFileDialog* self, out char16* pszName) GetFileName; + public function HResult(COM_IFileDialog* self, char16* pszTitle) SetTitle; + public function HResult(COM_IFileDialog* self, char16* pszText) SetOkButtonLabel; + public function HResult(COM_IFileDialog* self, char16* pszLabel) SetFileNameLabel; + public function HResult(COM_IFileDialog* self, out COM_IShellItem* ppsi) GetResult; + public function HResult(COM_IFileDialog* self, COM_IShellItem* psi, FDAP fdap) AddPlace; + public function HResult(COM_IFileDialog* self, char16* pszDefaultExtension) SetDefaultExtension; + public function HResult(COM_IFileDialog* self, int hr) Close; + public function HResult(COM_IFileDialog* self, ref Guid guid) SetClientGuid; + public function HResult(COM_IFileDialog* self) ClearClientData; + public function HResult(COM_IFileDialog* self, void* pFilter) SetFilter; + } + public new VTable* VT + { + get + { + return (.)mVT; + } + } + } + + public struct COM_IFileSaveDialog : COM_IFileDialog + { + public static new Guid sIID = .(0x84BCCD23, 0x5FDE, 0x4CDB, 0xAE, 0xA4, 0xAF, 0x64, 0xB8, 0x3D, 0x78, 0xAB); + public static new Guid sCLSID = .(0xC0B4E2F3, 0xBA21, 0x4773, 0x8D, 0xBA, 0x33, 0x5E, 0xC9, 0x46, 0xEB, 0x8B); + } + + public struct COM_IFileOpenDialog : COM_IFileDialog + { + public static new Guid sIID = .(0xD57C7288, 0xD4AD, 0x4768, 0xBE, 0x02, 0x9D, 0x96, 0x95, 0x32, 0xD9, 0x60); + + public struct VTable : COM_IFileDialog.VTable + { + public function HResult(COM_IFileOpenDialog* self, out COM_IShellItemArray* ppenum) GetResults; + public function HResult(COM_IFileOpenDialog* self, out COM_IShellItemArray* ppsai) GetSelectedItems; + } + public new VTable* VT + { + get + { + return (.)mVT; + } + } + } + [Import("version.lib"), CLink, CallingConvention(.Stdcall)] public static extern IntBool GetFileVersionInfoW(char16* lptstrFilename, uint32 dwHandle, uint32 dwLen, void* lpData); From 7864f83c4d2372ca798a355c3f8d65b53523e489 Mon Sep 17 00:00:00 2001 From: unknown <81806010+marsej@users.noreply.github.com> Date: Tue, 7 Dec 2021 16:39:37 +0200 Subject: [PATCH 003/139] Changed SDL initial bg color from white to black to remove white flash effect with some GPUs --- BeefLibs/SDL2/src/SDLApp.bf | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/BeefLibs/SDL2/src/SDLApp.bf b/BeefLibs/SDL2/src/SDLApp.bf index cc95a8dd..01535fe8 100644 --- a/BeefLibs/SDL2/src/SDLApp.bf +++ b/BeefLibs/SDL2/src/SDLApp.bf @@ -117,8 +117,12 @@ namespace SDL2 SDL.EventState(.JoyDeviceAdded, .Disable); SDL.EventState(.JoyDeviceRemoved, .Disable); - mWindow = SDL.CreateWindow(mTitle, .Undefined, .Undefined, mWidth, mHeight, .Shown); + mWindow = SDL.CreateWindow(mTitle, .Undefined, .Undefined, mWidth, mHeight, .Hidden); mRenderer = SDL.CreateRenderer(mWindow, -1, .Accelerated); + SDL.ShowWindow(mWindow); + SDL.SetRenderDrawColor(mRenderer, 0, 0, 0, 255); + SDL.RenderClear(mRenderer); + SDL.RenderPresent(mRenderer); mScreen = SDL.GetWindowSurface(mWindow); SDLImage.Init(.PNG | .JPG); mHasAudio = SDLMixer.OpenAudio(44100, SDLMixer.MIX_DEFAULT_FORMAT, 2, 4096) >= 0; From 32966b79a6a90e84d8dedf4164740500e28a82bf Mon Sep 17 00:00:00 2001 From: EinBurgbauer Date: Thu, 9 Dec 2021 19:34:01 +0100 Subject: [PATCH 004/139] buffered stream seek accepts everything by default + fromEnd fix --- BeefLibs/corlib/src/IO/BufferedStream.bf | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/BeefLibs/corlib/src/IO/BufferedStream.bf b/BeefLibs/corlib/src/IO/BufferedStream.bf index 91bf3a37..be432b08 100644 --- a/BeefLibs/corlib/src/IO/BufferedStream.bf +++ b/BeefLibs/corlib/src/IO/BufferedStream.bf @@ -19,7 +19,7 @@ namespace System.IO set { - mPos = Math.Min(value, Length); + mPos = value; } } @@ -43,20 +43,16 @@ namespace System.IO public override Result Seek(int64 pos, SeekKind seekKind = .Absolute) { - int64 length = Length; - - int64 newPos; switch (seekKind) { case .Absolute: - mPos = Math.Min(pos, length); - if (pos > length) - return .Err; + mPos = pos; case .FromEnd: - newPos = length - pos; + mPos = Length + pos; case .Relative: - mPos = Math.Min(mPos + pos, length); + mPos = mPos + pos; } + return .Ok; } From e13f194c6fb00f586df8aec45f9fdb4d6b41714c Mon Sep 17 00:00:00 2001 From: EinBurgbauer Date: Thu, 9 Dec 2021 20:04:17 +0100 Subject: [PATCH 005/139] make BufferedFileStream act like UnbufferedFileStream --- BeefLibs/corlib/src/IO/FileStream.bf | 30 ++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/BeefLibs/corlib/src/IO/FileStream.bf b/BeefLibs/corlib/src/IO/FileStream.bf index 25cb1607..de46955a 100644 --- a/BeefLibs/corlib/src/IO/FileStream.bf +++ b/BeefLibs/corlib/src/IO/FileStream.bf @@ -296,6 +296,15 @@ namespace System.IO } } + public override int64 Position + { + set + { + // Matches the behavior of Platform.BfpFile_Seek(mBfpFile, value, .Absolute); + mPos = Math.Max(value, 0); + } + } + public this() { @@ -416,6 +425,27 @@ namespace System.IO mFileAccess = access; } + public override Result Seek(int64 pos, SeekKind seekKind = .Absolute) + { + int64 newPos; + switch (seekKind) + { + case .Absolute: + newPos = pos; + case .FromEnd: + newPos = Length + pos; + case .Relative: + newPos = mPos + pos; + } + + // Matches the behaviour of Platform.BfpFile_Seek(mBfpFile, value, .Absolute); + mPos = Math.Max(newPos, 0); + if (seekKind == .Absolute && newPos < 0) + return .Err; + + return .Ok; + } + public override Result Close() { let ret = base.Close(); From b3cf28f50036092d333157e7a52e08a23a24d502 Mon Sep 17 00:00:00 2001 From: unknown <81806010+marsej@users.noreply.github.com> Date: Sat, 11 Dec 2021 05:58:45 +0200 Subject: [PATCH 006/139] Added ToggleCommentAlt for who prefer multi-line // comments --- IDE/src/ui/SourceEditWidgetContent.bf | 141 ++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) diff --git a/IDE/src/ui/SourceEditWidgetContent.bf b/IDE/src/ui/SourceEditWidgetContent.bf index dbb19ef7..d632f9a7 100644 --- a/IDE/src/ui/SourceEditWidgetContent.bf +++ b/IDE/src/ui/SourceEditWidgetContent.bf @@ -2238,6 +2238,147 @@ namespace IDE.ui return false; } + public bool ToggleCommentAlt(bool? doComment = null) + { + if (CheckReadOnly()) + return false; + bool noStar = false; + if ((!HasSelection()) && (doComment != null)) + { + CursorToLineEnd(); + int cursorEndPos = CursorTextPos; + CursorToLineStart(false); + mSelection = .(CursorTextPos, cursorEndPos); + noStar = true; + } + + if ((HasSelection()) && (mSelection.Value.Length > 0)) + { + var startLineAndCol = CursorLineAndColumn; + + UndoBatchStart undoBatchStart = new UndoBatchStart("embeddedToggleComment"); + mData.mUndoManager.Add(undoBatchStart); + + mData.mUndoManager.Add(new SetCursorAction(this)); + + int minPos = mSelection.GetValueOrDefault().MinPos; + int maxPos = mSelection.GetValueOrDefault().MaxPos; + mSelection = null; + + var str = scope String(); + ExtractString(minPos, maxPos - minPos, str); + var trimmedStr = scope String(); + trimmedStr.Append(str); + int32 startLen = (int32)trimmedStr.Length; + trimmedStr.TrimStart(); + int32 afterTrimStart = (int32)trimmedStr.Length; + trimmedStr.TrimEnd(); + int32 afterTrimEnd = (int32)trimmedStr.Length; + trimmedStr.Append('\n'); + + int firstCharPos = minPos + (startLen - afterTrimStart); + int lastCharPos = maxPos - (afterTrimStart - afterTrimEnd); + if ((doComment != true) && (trimmedStr.Contains("//"))) + { + for (int i = firstCharPos; i < lastCharPos - 1; i++) + { + if (minPos == 0 || (minPos>0 && SafeGetChar(i - 1) == '\n' || SafeGetChar(i - 1) == '\t')) + if (SafeGetChar(i - 0) == '/' && SafeGetChar(i + 1) == '/') + { + mSelection = EditSelection(i - 0, i + 2); + DeleteSelection(); + lastCharPos -= 2; + while (i < maxPos && SafeGetChar(i) != '\n') + { + i++; + } + } + } + mSelection = EditSelection(minPos, lastCharPos); + } + int q = 0; + var nc = trimmedStr.Count('\n'); + if ((doComment != true) && (trimmedStr.StartsWith("/*"))) + { + if (trimmedStr.EndsWith("*/\n")) + { + mSelection = EditSelection(firstCharPos, firstCharPos + 2); + DeleteChar(); + mSelection = EditSelection(lastCharPos - 4, lastCharPos - 2); + DeleteChar(); + + if (doComment != null) + mSelection = EditSelection(firstCharPos, lastCharPos - 4); + } + } + else if (doComment != false && nc<=1 && minPos >=0 && (SafeGetChar(minPos-1) != ' ' && SafeGetChar(minPos-1) != '\t') && SafeGetChar(minPos-1) != '\n') + { //if selection is from beginning of the line then we want to use // comment, that's why the check for line count and ' ' and tab + CursorTextPos = firstCharPos; + if (noStar) { + CursorTextPos = minPos; + + InsertAtCursor("//"); //goes here if no selection + } + else + { + InsertAtCursor("/*"); + CursorTextPos = lastCharPos + 2; + InsertAtCursor("*/"); + } + if (!noStar && doComment != null) + mSelection = EditSelection(firstCharPos, lastCharPos + 4); + } + else if (doComment != false && nc>=1 && minPos >0 && (SafeGetChar(maxPos-1) != ' ' && SafeGetChar(maxPos-1) != '\t') && SafeGetChar(maxPos-1) != '\n') + { + CursorTextPos = firstCharPos; + if (noStar) { + CursorTextPos = minPos; + + InsertAtCursor("//"); //goes here if no selection + } + else + { + InsertAtCursor("/*"); + CursorTextPos = lastCharPos + 2; + InsertAtCursor("*/"); + } + if (!noStar && doComment != null) + mSelection = EditSelection(firstCharPos, lastCharPos + 4); + } + else if (doComment != false) + { + while (firstCharPos >= 0 && SafeGetChar(firstCharPos) != '\n') + { + firstCharPos--; + } + + for (int i = firstCharPos + 1; i < maxPos + q; i++) + { + CursorTextPos = i; // needed to add i < maxPos + q; for this to work with InsertAtCursor + InsertAtCursor("//"); q++; q++; + + while (SafeGetChar(i) != '\n' && i < maxPos + q) + { + i++; + } + } + mSelection = EditSelection(minPos, maxPos + q); + } + + if (undoBatchStart != null) + mData.mUndoManager.Add(undoBatchStart.mBatchEnd); + + CursorLineAndColumn = startLineAndCol; + + if (doComment == null) + mSelection = null; + + return true; + } + + return false; + } + public void DeleteAllRight() { int startPos; From 20261f5d0dd0bbd44ad218908b4f936129350467 Mon Sep 17 00:00:00 2001 From: unknown <81806010+marsej@users.noreply.github.com> Date: Sat, 11 Dec 2021 06:02:11 +0200 Subject: [PATCH 007/139] Added ToggleCommentAlt as Toggle comments alternate style under Settings/Editor --- IDE/src/Settings.bf | 2 ++ IDE/src/ui/SettingsDialog.bf | 2 +- IDE/src/ui/SourceEditWidgetContent.bf | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/IDE/src/Settings.bf b/IDE/src/Settings.bf index 6065643e..f31aed7b 100644 --- a/IDE/src/Settings.bf +++ b/IDE/src/Settings.bf @@ -650,6 +650,7 @@ namespace IDE sd.Add("EnableFileRecovery", mEnableFileRecovery); sd.Add("FormatOnSave", mFormatOnSave); sd.Add("SyncWithWorkspacePanel", mSyncWithWorkspacePanel); + sd.Add("ToggleCommentAlt", mToggleCommentAlt); } public void Deserialize(StructuredData sd) @@ -679,6 +680,7 @@ namespace IDE sd.GetEnum("EnableFileRecovery", ref mEnableFileRecovery); sd.Get("FormatOnSave", ref mFormatOnSave); sd.Get("SyncWithWorkspacePanel", ref mSyncWithWorkspacePanel); + sd.Get("ToggleCommentAlt", ref mToggleCommentAlt); } public void SetDefaults() diff --git a/IDE/src/ui/SettingsDialog.bf b/IDE/src/ui/SettingsDialog.bf index 38cf60b3..8c8026c0 100644 --- a/IDE/src/ui/SettingsDialog.bf +++ b/IDE/src/ui/SettingsDialog.bf @@ -126,7 +126,7 @@ namespace IDE.ui AddPropertiesItem(category, "Enable File Recovery", "mEnableFileRecovery"); AddPropertiesItem(category, "Format on Save", "mFormatOnSave"); AddPropertiesItem(category, "Sync with Workspace Panel", "mSyncWithWorkspacePanel"); - + AddPropertiesItem(category, "Toggle comment alternate style", "mToggleCommentAlt"); category.Open(true, true); } diff --git a/IDE/src/ui/SourceEditWidgetContent.bf b/IDE/src/ui/SourceEditWidgetContent.bf index d632f9a7..4f66ffbd 100644 --- a/IDE/src/ui/SourceEditWidgetContent.bf +++ b/IDE/src/ui/SourceEditWidgetContent.bf @@ -2162,6 +2162,8 @@ namespace IDE.ui public bool ToggleComment(bool? doComment = null) { + if (gApp.mSettings.mEditorSettings.mToggleCommentAlt) return ToggleCommentAlt(doComment); + if (CheckReadOnly()) return false; From 6e011678b473a3911958fff91f23770e9be7c0dd Mon Sep 17 00:00:00 2001 From: unknown <81806010+marsej@users.noreply.github.com> Date: Sat, 11 Dec 2021 06:15:53 +0200 Subject: [PATCH 008/139] fix whitespace --- IDE/src/ui/SourceEditWidgetContent.bf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/IDE/src/ui/SourceEditWidgetContent.bf b/IDE/src/ui/SourceEditWidgetContent.bf index 4f66ffbd..a3d94bd9 100644 --- a/IDE/src/ui/SourceEditWidgetContent.bf +++ b/IDE/src/ui/SourceEditWidgetContent.bf @@ -2295,7 +2295,7 @@ namespace IDE.ui i++; } } - } + } mSelection = EditSelection(minPos, lastCharPos); } int q = 0; @@ -2355,7 +2355,7 @@ namespace IDE.ui } for (int i = firstCharPos + 1; i < maxPos + q; i++) - { + { CursorTextPos = i; // needed to add i < maxPos + q; for this to work with InsertAtCursor InsertAtCursor("//"); q++; q++; @@ -2365,7 +2365,7 @@ namespace IDE.ui } } mSelection = EditSelection(minPos, maxPos + q); - } + } if (undoBatchStart != null) mData.mUndoManager.Add(undoBatchStart.mBatchEnd); From 14bf2addd99cd3ecacba2488738a9a6d810135a9 Mon Sep 17 00:00:00 2001 From: unknown <81806010+marsej@users.noreply.github.com> Date: Sat, 11 Dec 2021 06:20:46 +0200 Subject: [PATCH 009/139] add blank line back --- IDE/src/ui/SettingsDialog.bf | 1 + 1 file changed, 1 insertion(+) diff --git a/IDE/src/ui/SettingsDialog.bf b/IDE/src/ui/SettingsDialog.bf index 8c8026c0..7f602893 100644 --- a/IDE/src/ui/SettingsDialog.bf +++ b/IDE/src/ui/SettingsDialog.bf @@ -127,6 +127,7 @@ namespace IDE.ui AddPropertiesItem(category, "Format on Save", "mFormatOnSave"); AddPropertiesItem(category, "Sync with Workspace Panel", "mSyncWithWorkspacePanel"); AddPropertiesItem(category, "Toggle comment alternate style", "mToggleCommentAlt"); + category.Open(true, true); } From 8522ca42165b0174c358fe6b181a63dedd048fb7 Mon Sep 17 00:00:00 2001 From: unknown <81806010+marsej@users.noreply.github.com> Date: Sat, 11 Dec 2021 07:02:11 +0200 Subject: [PATCH 010/139] commenting blank now does nothing --- IDE/src/ui/SourceEditWidgetContent.bf | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/IDE/src/ui/SourceEditWidgetContent.bf b/IDE/src/ui/SourceEditWidgetContent.bf index a3d94bd9..bb06a5c2 100644 --- a/IDE/src/ui/SourceEditWidgetContent.bf +++ b/IDE/src/ui/SourceEditWidgetContent.bf @@ -2280,7 +2280,23 @@ namespace IDE.ui int firstCharPos = minPos + (startLen - afterTrimStart); int lastCharPos = maxPos - (afterTrimStart - afterTrimEnd); - if ((doComment != true) && (trimmedStr.Contains("//"))) + + int q = 0; + var nc = trimmedStr.Count('\n'); + + if(afterTrimEnd == 0) + { + if (undoBatchStart != null) + mData.mUndoManager.Add(undoBatchStart.mBatchEnd); + + CursorLineAndColumn = startLineAndCol; + + if (doComment == null) + mSelection = null; + + return false; // not sure if this should be false in blank/only whitespace selection case + } + else if ((doComment != true) && (trimmedStr.Contains("//"))) { for (int i = firstCharPos; i < lastCharPos - 1; i++) { @@ -2298,9 +2314,7 @@ namespace IDE.ui } mSelection = EditSelection(minPos, lastCharPos); } - int q = 0; - var nc = trimmedStr.Count('\n'); - if ((doComment != true) && (trimmedStr.StartsWith("/*"))) + else if ((doComment != true) && (trimmedStr.StartsWith("/*"))) { if (trimmedStr.EndsWith("*/\n")) { From 73099e4a04f5674bbf46ff57d0acdb7d9f70cd17 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Sat, 11 Dec 2021 09:08:42 -0800 Subject: [PATCH 011/139] Code generator support --- BeefLibs/Beefy2D/src/widgets/Dialog.bf | 3 + BeefLibs/corlib/src/Compiler.bf | 182 +++++- IDE/src/CommandQueueManager.bf | 16 +- IDE/src/Compiler/BfCompiler.bf | 34 +- IDE/src/Project.bf | 2 + IDE/src/ui/ClassViewPanel.bf | 4 + IDE/src/ui/GenerateDialog.bf | 869 +++++++++++++++++++++++++ IDE/src/ui/OutputPanel.bf | 2 +- IDE/src/ui/ProjectPanel.bf | 104 ++- IDEHelper/Compiler/BfCompiler.cpp | 275 ++++++-- IDEHelper/Compiler/BfCompiler.h | 11 +- IDEHelper/Compiler/BfExprEvaluator.cpp | 16 +- IDEHelper/Compiler/BfModule.cpp | 19 +- IDEHelper/Compiler/BfModule.h | 1 + IDEHelper/Compiler/CeMachine.cpp | 17 +- 15 files changed, 1472 insertions(+), 83 deletions(-) create mode 100644 IDE/src/ui/GenerateDialog.bf diff --git a/BeefLibs/Beefy2D/src/widgets/Dialog.bf b/BeefLibs/Beefy2D/src/widgets/Dialog.bf index b879a7e0..01723f6b 100644 --- a/BeefLibs/Beefy2D/src/widgets/Dialog.bf +++ b/BeefLibs/Beefy2D/src/widgets/Dialog.bf @@ -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; diff --git a/BeefLibs/corlib/src/Compiler.bf b/BeefLibs/corlib/src/Compiler.bf index 45a8e3c3..ff90fc24 100644 --- a/BeefLibs/corlib/src/Compiler.bf +++ b/BeefLibs/corlib/src/Compiler.bf @@ -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 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 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() 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(String args) where T : Generator + { + T val = scope T(); + val.HandleArgs(args); + val.InitUI(); + return val.mCmdInfo; + } + + static String Generate(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; diff --git a/IDE/src/CommandQueueManager.bf b/IDE/src/CommandQueueManager.bf index 213fee60..4fa97410 100644 --- a/IDE/src/CommandQueueManager.bf +++ b/IDE/src/CommandQueueManager.bf @@ -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() diff --git a/IDE/src/Compiler/BfCompiler.bf b/IDE/src/Compiler/BfCompiler.bf index e00b3502..d391831a 100644 --- a/IDE/src/Compiler/BfCompiler.bf +++ b/IDE/src/Compiler/BfCompiler.bf @@ -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)); diff --git a/IDE/src/Project.bf b/IDE/src/Project.bf index 7418ea2a..1a485c0d 100644 --- a/IDE/src/Project.bf +++ b/IDE/src/Project.bf @@ -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(); } } diff --git a/IDE/src/ui/ClassViewPanel.bf b/IDE/src/ui/ClassViewPanel.bf index 3088cccc..51fac019 100644 --- a/IDE/src/ui/ClassViewPanel.bf +++ b/IDE/src/ui/ClassViewPanel.bf @@ -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')) { diff --git a/IDE/src/ui/GenerateDialog.bf b/IDE/src/ui/GenerateDialog.bf new file mode 100644 index 00000000..2d50da64 --- /dev/null +++ b/IDE/src/ui/GenerateDialog.bf @@ -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 sMRU = new Dictionary() ~ delete _; + public static int32 sCurrentMRUIndex = 1; + + public GenerateDialog mNewClassDialog; + public List mEntries = new List() ~ DeleteContainerAndItems!(_); + public List mShownEntries = new List() ~ 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 findStrs = null; + if (mFilterString != null) + findStrs = scope:: List(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 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 oldEntries = scope .(); + Dictionary 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 choices = new List(); + 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; + } + } +} diff --git a/IDE/src/ui/OutputPanel.bf b/IDE/src/ui/OutputPanel.bf index 8d002fa1..e99e10a6 100644 --- a/IDE/src/ui/OutputPanel.bf +++ b/IDE/src/ui/OutputPanel.bf @@ -327,7 +327,7 @@ namespace IDE.ui int lineIdx = (curLine + lineOfs) % lineCount; if (content.GotoRefrenceAtLine(lineIdx)) - break; + break; } } diff --git a/IDE/src/ui/ProjectPanel.bf b/IDE/src/ui/ProjectPanel.bf index 0019a29e..fedf9188 100644 --- a/IDE/src/ui/ProjectPanel.bf +++ b/IDE/src/ui/ProjectPanel.bf @@ -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();*/ }); diff --git a/IDEHelper/Compiler/BfCompiler.cpp b/IDEHelper/Compiler/BfCompiler.cpp index f7757a1d..9be06ac6 100644 --- a/IDEHelper/Compiler/BfCompiler.cpp +++ b/IDEHelper/Compiler/BfCompiler.cpp @@ -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 prevMethodInstance(mContext->mUnreifiedModule->mCurMethodInstance, moduleMethodInstance.mMethodInstance); + SetAndRestoreValue prevTypeInstance(mContext->mUnreifiedModule->mCurTypeInstance, typeInst); + + BfExprEvaluator exprEvaluator(mContext->mUnreifiedModule); + exprEvaluator.mBfEvalExprFlags = BfEvalExprFlags_Comptime; + + SizedArray 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 projectIds; + + BfResolvePassData resolvePassData; + SetAndRestoreValue prevResolvePassData(mResolvePassData, &resolvePassData); + BfPassInstance passInstance(mSystem); + SetAndRestoreValue 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 prevResolvePassData(mResolvePassData, &resolvePassData); + BfPassInstance passInstance(mSystem); + SetAndRestoreValue prevPassInstance(mPassInstance, &passInstance); + + Array 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 prevResolvePassData(mResolvePassData, &resolvePassData); + BfPassInstance passInstance(mSystem); + SetAndRestoreValue prevPassInstance(mPassInstance, &passInstance); + + Array 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& 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 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(); diff --git a/IDEHelper/Compiler/BfCompiler.h b/IDEHelper/Compiler/BfCompiler.h index d859da0f..9c2dbef6 100644 --- a/IDEHelper/Compiler/BfCompiler.h +++ b/IDEHelper/Compiler/BfCompiler.h @@ -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& typeDefs); String GetTypeDefInfo(const StringImpl& typeName); int GetEmitSource(const StringImpl& fileName, StringImpl* outBuffer); diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index e6d3ba2b..0650b7fa 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -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 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) diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index f9074614..b0a48ebb 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -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 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); diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index 30a11776..efa5ae8f 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -1633,6 +1633,7 @@ public: bool IsTargetingBeefBackend(); bool WantsLifetimes(); bool HasCompiledOutput(); + bool HasExecutedOutput(); void SkipObjectAccessCheck(BfTypedValue typedVal); void EmitObjectAccessCheck(BfTypedValue typedVal); void EmitEnsureInstructionAt(); diff --git a/IDEHelper/Compiler/CeMachine.cpp b/IDEHelper/Compiler/CeMachine.cpp index 0b9384c3..4a843de2 100644 --- a/IDEHelper/Compiler/CeMachine.cpp +++ b/IDEHelper/Compiler/CeMachine.cpp @@ -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 From 9210f2f925b6d7026070046e235314097793e82d Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Sat, 11 Dec 2021 09:47:42 -0800 Subject: [PATCH 012/139] Static init fix --- IDEHelper/Compiler/BfModule.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index b0a48ebb..439aab4d 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -15823,7 +15823,7 @@ void BfModule::CreateStaticCtor() auto methodDef = mCurMethodInstance->mMethodDef; BfIRBlock exitBB; - if ((HasExecutedOutput()) && (!mCurMethodInstance->mIsUnspecialized) && (mCurMethodInstance->mChainType != BfMethodChainType_ChainMember)) + if ((HasCompiledOutput()) && (!mCurMethodInstance->mIsUnspecialized) && (mCurMethodInstance->mChainType != BfMethodChainType_ChainMember)) { auto boolType = GetPrimitiveType(BfTypeCode_Boolean); auto didStaticInitVarAddr = mBfIRBuilder->CreateGlobalVariable( From f17ed3c7497bb4276b7fbd441a1254c1538f5438 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Sat, 11 Dec 2021 10:02:15 -0800 Subject: [PATCH 013/139] Fix for clicking OK button --- IDE/src/ui/GenerateDialog.bf | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/IDE/src/ui/GenerateDialog.bf b/IDE/src/ui/GenerateDialog.bf index 2d50da64..eb6eb700 100644 --- a/IDE/src/ui/GenerateDialog.bf +++ b/IDE/src/ui/GenerateDialog.bf @@ -256,7 +256,11 @@ namespace IDE.ui mWindowFlags = .ClientSized | .TopMost | .Caption | .Border | .SysMenu | .Resizable | .PopupPosition; - AddOkCancelButtons(new (evt) => { CreateClass(); }, null, 0, 1); + AddOkCancelButtons(new (evt) => + { + Submit(); + evt.mCloseDialog = false; + }, null, 0, 1); Title = "Generate"; @@ -486,11 +490,6 @@ namespace IDE.ui mWidgetWindow.SetMinimumSize(GS!(240), (.)mUIHeight + GS!(24), true); } - void CreateClass() - { - //mClassViewPanel.[Friend]mSearchEdit.mOnSubmit(null); - } - void ShowError(StringView error) { if (mOutputPanel == null) From bc996ca471f5c6154556ff0ffab0da5678c25eaf Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Sat, 11 Dec 2021 10:45:40 -0800 Subject: [PATCH 014/139] Change label --- IDE/src/ui/GenerateDialog.bf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IDE/src/ui/GenerateDialog.bf b/IDE/src/ui/GenerateDialog.bf index eb6eb700..df18cfab 100644 --- a/IDE/src/ui/GenerateDialog.bf +++ b/IDE/src/ui/GenerateDialog.bf @@ -788,7 +788,7 @@ namespace IDE.ui g.DrawString(label, widget.mX + GS!(6), widget.mY - GS!(20)); } - DrawLabel(mKindBar, mRegenerating ? "Regenerating ..." : "Using Generator"); + DrawLabel(mKindBar, mRegenerating ? "Regenerating ..." : "Generator"); for (var uiEntry in mUIEntries) DrawLabel(uiEntry.mWidget, uiEntry.mLabel); } @@ -848,7 +848,7 @@ namespace IDE.ui if (mThreadState == .Executing) { var bfCompiler = gApp.mBfResolveCompiler; - bfCompiler.RequestFastFinish(); + bfCompiler.RequestFastFinish(true); bfCompiler.WaitForBackground(); } base.Close(); From d57e790a9aea0faf9fe1da5b763a9845987f2140 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Sat, 11 Dec 2021 10:46:21 -0800 Subject: [PATCH 015/139] Formatting fixes - lambda dtor, space before comments --- IDEHelper/Compiler/BfPrinter.cpp | 54 ++++++++++++++++++++++++-------- IDEHelper/Compiler/BfPrinter.h | 1 + 2 files changed, 42 insertions(+), 13 deletions(-) diff --git a/IDEHelper/Compiler/BfPrinter.cpp b/IDEHelper/Compiler/BfPrinter.cpp index ccc2d82e..f30db3a9 100644 --- a/IDEHelper/Compiler/BfPrinter.cpp +++ b/IDEHelper/Compiler/BfPrinter.cpp @@ -300,6 +300,11 @@ int BfPrinter::CalcOrigLineSpacing(BfAstNode* bfAstNode, int* lineStartIdx) void BfPrinter::WriteIgnoredNode(BfAstNode* node) { + if ((!mOutString.IsEmpty()) && (!isspace((uint8)mOutString[mOutString.mLength - 1]))) + { + Write(" "); + } + bool wasExpectingNewLine = mExpectingNewLine; mTriviaIdx = std::max(mTriviaIdx, node->GetTriviaStart()); @@ -1759,9 +1764,14 @@ void BfPrinter::Visit(BfLambdaBindExpression* lambdaBindExpr) else { ExpectSpace(); - VisitChild(lambdaBindExpr->mBody); + VisitChild(lambdaBindExpr->mBody); } - } + } + VisitChild(lambdaBindExpr->mDtor); + mNextStateModify.mExpectingSpace = false; + mVirtualNewLineIdx = mNextStateModify.mWantNewLineIdx; + mCurIndentLevel = mNextStateModify.mWantVirtualIndent; + mVirtualIndentLevel = mNextStateModify.mWantVirtualIndent; } void BfPrinter::Visit(BfObjectCreateExpression* newExpr) @@ -2643,7 +2653,7 @@ void BfPrinter::Visit(BfIndexerDeclaration* indexerDeclaration) } void BfPrinter::Visit(BfFieldDeclaration* fieldDeclaration) -{ +{ bool isEnumDecl = false; if (auto enumEntry = BfNodeDynCast(fieldDeclaration)) @@ -2703,18 +2713,10 @@ void BfPrinter::Visit(BfFieldDeclaration* fieldDeclaration) QueueVisitChild(fieldDeclaration->mInitializer); } - auto fieldDtor = fieldDeclaration->mFieldDtor; - while (fieldDtor != NULL) - { - ExpectSpace(); - QueueVisitChild(fieldDtor->mTildeToken); - ExpectSpace(); - QueueVisitChild(fieldDtor->mBody); - fieldDtor = fieldDtor->mNextFieldDtor; - } - mNextStateModify.mExpectingSpace = false; FlushVisitChild(); + VisitChild(fieldDeclaration->mFieldDtor); + mNextStateModify.mExpectingSpace = false; } void BfPrinter::Visit(BfEnumCaseDeclaration* enumCaseDeclaration) @@ -2763,6 +2765,32 @@ void BfPrinter::Visit(BfTypeAliasDeclaration* typeDeclaration) VisitChild(typeDeclaration->mEndSemicolon); } +void BfPrinter::Visit(BfFieldDtorDeclaration* fieldDtorDeclaration) +{ + ExpectSpace(); + if (fieldDtorDeclaration->mBody != NULL) + { + if (fieldDtorDeclaration->mBody->IsA()) + { + ExpectNewLine(); + ExpectIndent(); + VisitChild(fieldDtorDeclaration->mTildeToken); + VisitChild(fieldDtorDeclaration->mBody); + ExpectUnindent(); + } + else + { + VisitChild(fieldDtorDeclaration->mTildeToken); + ExpectSpace(); + VisitChild(fieldDtorDeclaration->mBody); + } + } + else + VisitChild(fieldDtorDeclaration->mTildeToken); + + VisitChild(fieldDtorDeclaration->mNextFieldDtor); +} + void BfPrinter::Visit(BfTypeDeclaration* typeDeclaration) { SetAndRestoreValue prevTypeDecl(mCurTypeDecl, typeDeclaration); diff --git a/IDEHelper/Compiler/BfPrinter.h b/IDEHelper/Compiler/BfPrinter.h index 815222c5..cf4dc2b6 100644 --- a/IDEHelper/Compiler/BfPrinter.h +++ b/IDEHelper/Compiler/BfPrinter.h @@ -220,6 +220,7 @@ public: virtual void Visit(BfFieldDeclaration* fieldDeclaration) override; virtual void Visit(BfEnumCaseDeclaration* enumCaseDeclaration) override; virtual void Visit(BfTypeAliasDeclaration* typeDeclaration) override; + virtual void Visit(BfFieldDtorDeclaration* fieldDtorDeclaration) override; virtual void Visit(BfTypeDeclaration* typeDeclaration) override; virtual void Visit(BfUsingDirective* usingDirective) override; virtual void Visit(BfUsingModDirective* usingDirective) override; From cb6f88b047da0d067f47fb0a559940683ce22473 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Sat, 11 Dec 2021 10:49:12 -0800 Subject: [PATCH 016/139] Minlib fix --- IDE/mintest/minlib/src/System/Compiler.bf | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/IDE/mintest/minlib/src/System/Compiler.bf b/IDE/mintest/minlib/src/System/Compiler.bf index 2c559e2c..d6aefbda 100644 --- a/IDE/mintest/minlib/src/System/Compiler.bf +++ b/IDE/mintest/minlib/src/System/Compiler.bf @@ -2,6 +2,11 @@ namespace System { class Compiler { + public class Generator + { + + } + public static class Options { [LinkName("#AllocStackCount")] From 06d896330d61a53a284ecebe98049dfb413c799e Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Sat, 11 Dec 2021 12:27:53 -0800 Subject: [PATCH 017/139] Fixed processing error of sized array with size containing local variables --- IDEHelper/Compiler/BfExprEvaluator.cpp | 27 ++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 0650b7fa..e36dc52f 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -6373,16 +6373,23 @@ void BfExprEvaluator::FinishDeferredEvals(BfResolvedArgs& argValues) auto variableDeclaration = BfNodeDynCast((*argValues.mArguments)[argIdx]); if ((variableDeclaration != NULL) && (variableDeclaration->mNameNode != NULL)) { - BfLocalVariable* localVar = new BfLocalVariable(); - localVar->mName = variableDeclaration->mNameNode->ToString(); - localVar->mResolvedType = mModule->GetPrimitiveType(BfTypeCode_Var); - localVar->mAddr = mModule->mBfIRBuilder->GetFakeVal(); - localVar->mReadFromId = 0; - localVar->mWrittenToId = 0; - localVar->mAssignedKind = BfLocalVarAssignKind_Unconditional; - mModule->CheckVariableDef(localVar); - localVar->Init(); - mModule->AddLocalVariableDef(localVar, true); + if (mModule->mCurMethodState == NULL) + { + mModule->Fail("Illegal local variable", variableDeclaration); + } + else + { + BfLocalVariable* localVar = new BfLocalVariable(); + localVar->mName = variableDeclaration->mNameNode->ToString(); + localVar->mResolvedType = mModule->GetPrimitiveType(BfTypeCode_Var); + localVar->mAddr = mModule->mBfIRBuilder->GetFakeVal(); + localVar->mReadFromId = 0; + localVar->mWrittenToId = 0; + localVar->mAssignedKind = BfLocalVarAssignKind_Unconditional; + mModule->CheckVariableDef(localVar); + localVar->Init(); + mModule->AddLocalVariableDef(localVar, true); + } } } } From 9517b3a9d5753cb70f6c73278dc2244f598564a5 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Sat, 11 Dec 2021 12:48:51 -0800 Subject: [PATCH 018/139] AssertErrorState null check fix --- IDEHelper/Compiler/BfModule.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 439aab4d..bcb55092 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -15278,7 +15278,7 @@ void BfModule::AssertErrorState() { if (mCurTypeInstance->mTypeFailed) return; - if (mCurTypeInstance->mTypeDef->mSource->mParsingFailed) + if ((mCurTypeInstance->mTypeDef->mSource != NULL) && (mCurTypeInstance->mTypeDef->mSource->mParsingFailed)) return; } if (mCurMethodInstance != NULL) From 187fe8c4a5606dada8ef9fa2b848df9a158e914e Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Sat, 11 Dec 2021 13:01:22 -0800 Subject: [PATCH 019/139] More null checks --- IDEHelper/Compiler/BfModule.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index bcb55092..93e6d061 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -15283,9 +15283,11 @@ void BfModule::AssertErrorState() } if (mCurMethodInstance != NULL) { - if ((mCurMethodInstance->mMethodDef->mDeclaringType != NULL) && (mCurMethodInstance->mMethodDef->mDeclaringType->mSource->mParsingFailed)) + if ((mCurMethodInstance->mMethodDef->mDeclaringType != NULL) && (mCurMethodInstance->mMethodDef->mDeclaringType != NULL) && (mCurMethodInstance->mMethodDef->mDeclaringType->mSource->mParsingFailed)) return; - if ((mCurMethodState != NULL) && (mCurMethodState->mMixinState != NULL) && (mCurMethodState->mMixinState->mMixinMethodInstance->mMethodDef->mDeclaringType->mSource->mParsingFailed)) + if ((mCurMethodState != NULL) && (mCurMethodState->mMixinState != NULL) && + (mCurMethodState->mMixinState->mMixinMethodInstance->mMethodDef->mDeclaringType->mSource != NULL) && + (mCurMethodState->mMixinState->mMixinMethodInstance->mMethodDef->mDeclaringType->mSource->mParsingFailed)) return; } From d0f083446310c8fd2423ee3bf66eaf5a571625c4 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Sat, 11 Dec 2021 16:21:37 -0800 Subject: [PATCH 020/139] Fix null check --- IDEHelper/Compiler/BfModule.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 93e6d061..855e958d 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -15283,7 +15283,9 @@ void BfModule::AssertErrorState() } if (mCurMethodInstance != NULL) { - if ((mCurMethodInstance->mMethodDef->mDeclaringType != NULL) && (mCurMethodInstance->mMethodDef->mDeclaringType != NULL) && (mCurMethodInstance->mMethodDef->mDeclaringType->mSource->mParsingFailed)) + if ((mCurMethodInstance->mMethodDef->mDeclaringType != NULL) && + (mCurMethodInstance->mMethodDef->mDeclaringType->mSource != NULL) && + (mCurMethodInstance->mMethodDef->mDeclaringType->mSource->mParsingFailed)) return; if ((mCurMethodState != NULL) && (mCurMethodState->mMixinState != NULL) && (mCurMethodState->mMixinState->mMixinMethodInstance->mMethodDef->mDeclaringType->mSource != NULL) && From 506f5b7d5d6eea96d5c88076041b67f6a64c27d7 Mon Sep 17 00:00:00 2001 From: EinBurgbauer Date: Sun, 12 Dec 2021 13:10:30 +0100 Subject: [PATCH 021/139] file generation dropdown changes, dialog fix --- IDE/src/ui/GenerateDialog.bf | 6 ++++-- IDE/src/ui/ProjectPanel.bf | 21 ++++++++++----------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/IDE/src/ui/GenerateDialog.bf b/IDE/src/ui/GenerateDialog.bf index df18cfab..bd870f94 100644 --- a/IDE/src/ui/GenerateDialog.bf +++ b/IDE/src/ui/GenerateDialog.bf @@ -262,7 +262,7 @@ namespace IDE.ui evt.mCloseDialog = false; }, null, 0, 1); - Title = "Generate"; + Title = "Generate File"; mKindBar = new GenerateKindBar(this); AddWidget(mKindBar); @@ -312,7 +312,7 @@ namespace IDE.ui if ((generatorName == default) || (hash == default)) { Close(); - gApp.Fail(scope $"File '{filePath}' was not generated by a generator that include regeneration information"); + gApp.Fail(scope $"File '{filePath}' was not generated by a generator that includes regeneration information"); return; } @@ -455,6 +455,8 @@ namespace IDE.ui if (line.StartsWith("!error")) { ShowError(line.Substring(7)); + + RehupMinSize(); continue; } diff --git a/IDE/src/ui/ProjectPanel.bf b/IDE/src/ui/ProjectPanel.bf index fedf9188..2e05a409 100644 --- a/IDE/src/ui/ProjectPanel.bf +++ b/IDE/src/ui/ProjectPanel.bf @@ -2456,7 +2456,15 @@ namespace IDE.ui }); } - if (let projectFolder = projectItem as ProjectFolder) + if (projectItem is ProjectSource) + { + item = menu.AddItem("Regenerate"); + item.mOnMenuItemSelected.Add(new (item) => + { + Regenerate(false); + }); + } + else if (let projectFolder = projectItem as ProjectFolder) { //if (projectFolder.mIncludeKind == .Manual) { @@ -2554,7 +2562,7 @@ namespace IDE.ui } }); - item = menu.AddItem("Generate..."); + item = menu.AddItem("Generate File..."); item.mOnMenuItemSelected.Add(new (item) => { var projectFolder = GetSelectedProjectFolder(); @@ -2565,15 +2573,6 @@ namespace IDE.ui } }); - 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();*/ }); From 969e7af49185247b7e5cc45a851786bfb056c36c Mon Sep 17 00:00:00 2001 From: unknown <81806010+marsej@users.noreply.github.com> Date: Mon, 13 Dec 2021 03:55:27 +0200 Subject: [PATCH 022/139] fix missing mToggleCommentAlt --- IDE/src/Settings.bf | 1 + 1 file changed, 1 insertion(+) diff --git a/IDE/src/Settings.bf b/IDE/src/Settings.bf index f31aed7b..d0012c42 100644 --- a/IDE/src/Settings.bf +++ b/IDE/src/Settings.bf @@ -625,6 +625,7 @@ namespace IDE public FileRecoveryKind mEnableFileRecovery = .Yes; public bool mFormatOnSave = false; public bool mSyncWithWorkspacePanel = false; + public bool mToggleCommentAlt = false; public void Serialize(StructuredData sd) { From c545e4ed371b22ec2ae86c35d353882fb14608ce Mon Sep 17 00:00:00 2001 From: disarray2077 <86157825+disarray2077@users.noreply.github.com> Date: Mon, 13 Dec 2021 10:36:31 -0300 Subject: [PATCH 023/139] Fix folder renaming --- IDE/src/Project.bf | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/IDE/src/Project.bf b/IDE/src/Project.bf index 1a485c0d..ce90f199 100644 --- a/IDE/src/Project.bf +++ b/IDE/src/Project.bf @@ -845,6 +845,13 @@ namespace IDE childFileItem.OnRename(childFileItem.mPath, newChildPath); + String oldFullName = scope String(); + mProject.GetProjectFullPath(childFileItem.mPath, oldFullName); + String newFullName = scope String(); + mProject.GetProjectFullPath(newChildPath, newFullName); + + IDEApp.sApp.FileRenamed(childFileItem, oldFullName, newFullName); + childFileItem.mPath.Set(newChildPath); } } From a1fd8d139790dcded201e220a6c28d4f1d186595 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 14 Dec 2021 09:51:25 -0500 Subject: [PATCH 024/139] Improve POD resize speed --- BeefySysLib/util/Array.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BeefySysLib/util/Array.h b/BeefySysLib/util/Array.h index e485023c..c5241db5 100644 --- a/BeefySysLib/util/Array.h +++ b/BeefySysLib/util/Array.h @@ -830,8 +830,8 @@ public: else if (size > this->mSize) { Reserve(size); - while (size > this->mSize) - this->mVals[this->mSize++] = T(); + memset(&this->mVals[this->mSize], 0, (size - this->mSize) * sizeof(T)); + this->mSize = (int_cosize)size; } } From 31af480c92431b3186e062fc10e5ffcbcff5a0f6 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 14 Dec 2021 09:52:37 -0500 Subject: [PATCH 025/139] Increase member chunk size to avoid linker crash --- IDEHelper/Backend/BeCOFFObject.cpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/IDEHelper/Backend/BeCOFFObject.cpp b/IDEHelper/Backend/BeCOFFObject.cpp index 3ef70a7a..5456c395 100644 --- a/IDEHelper/Backend/BeCOFFObject.cpp +++ b/IDEHelper/Backend/BeCOFFObject.cpp @@ -555,6 +555,7 @@ void BeCOFFObject::DbgTEndTag() BF_ASSERT(mTTagStartPos != -1); DbgTAlign(); int tagSize = mDebugTSect.mData.GetPos() - mTTagStartPos; + BF_ASSERT(tagSize <= 0xFFFF); *((int16*)&mDebugTSect.mData.mData[mTTagStartPos]) = (int16)(tagSize - 2); mTTagStartPos = -1; } @@ -597,11 +598,7 @@ int BeCOFFObject::DbgGetTypeId(BeDbgType* dbgType, bool doDefine) DbgGetTypeId(structType->mDerivedFrom); for (auto member : structType->mMembers) { - auto type = member->mType; - //TODO: - //if (member->mName == "VersionName") - //continue; - + auto type = member->mType; DbgGetTypeId(type); } for (auto func : structType->mMethods) @@ -627,7 +624,7 @@ int BeCOFFObject::DbgGetTypeId(BeDbgType* dbgType, bool doDefine) auto _CheckFieldOverflow = [&]() { int tagSize = mDebugTSect.mData.GetPos() - mTTagStartPos; - if (tagSize >= 2000) + if (tagSize >= 0xE000) { int extFieldListTag = mCurTagId++; @@ -1013,8 +1010,7 @@ void BeCOFFObject::DbgGenerateTypeInfo() void BeCOFFObject::DbgStartSection(int sectionNum) { auto& outS = mDebugSSect.mData; - BF_ASSERT(mSectionStartPos == -1); - + BF_ASSERT(mSectionStartPos == -1); outS.Write((int32)sectionNum); outS.Write(0); // Temporary - size mSectionStartPos = outS.GetPos(); @@ -1024,6 +1020,7 @@ void BeCOFFObject::DbgEndSection() { auto& outS = mDebugSSect.mData; int totalLen = outS.GetPos() - mSectionStartPos; + BF_ASSERT(totalLen <= 0xFFFF); *((int32*)&outS.mData[mSectionStartPos - 4]) = totalLen; mSectionStartPos = -1; while ((outS.GetPos() & 3) != 0) @@ -1132,7 +1129,7 @@ void BeCOFFObject::DbgSEndTag() { BF_ASSERT(mSTagStartPos != -1); int tagSize = mDebugSSect.mData.GetPos() - mSTagStartPos; - + BF_ASSERT(tagSize <= 0xFFFF); *((uint16*)&mDebugSSect.mData.mData[mSTagStartPos]) = (uint16)(tagSize - 2); mSTagStartPos = -1; } @@ -2146,7 +2143,7 @@ bool BeCOFFObject::Generate(BeModule* module, const StringImpl& fileName) if (mWriteToLib) { DynMemStream memStream; - + Generate(module); mStream = &memStream; From e871bd6ace729e51a0747f16b8203de736de123f Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 14 Dec 2021 09:53:43 -0500 Subject: [PATCH 026/139] Fixed erroneous char ptr const generation --- IDEHelper/Compiler/BfIRBuilder.cpp | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/IDEHelper/Compiler/BfIRBuilder.cpp b/IDEHelper/Compiler/BfIRBuilder.cpp index cc43725c..b524fdd9 100644 --- a/IDEHelper/Compiler/BfIRBuilder.cpp +++ b/IDEHelper/Compiler/BfIRBuilder.cpp @@ -2970,10 +2970,10 @@ void BfIRBuilder::CreateDbgTypeDefinition(BfType* type) diFieldTypes.push_back(memberType); } - bool isPayloadEnum = (typeInstance->IsEnum()) && (!typeInstance->IsTypedPrimitive()); - for (auto& fieldInstanceRef : typeInstance->mFieldInstances) + bool isPayloadEnum = (typeInstance->IsEnum()) && (!typeInstance->IsTypedPrimitive()); + for (int fieldIdx = 0; fieldIdx < typeInstance->mFieldInstances.mSize; fieldIdx++) { - auto fieldInstance = &fieldInstanceRef; + auto fieldInstance = &typeInstance->mFieldInstances[fieldIdx]; if (!fieldInstance->mFieldIncluded) continue; auto fieldDef = fieldInstance->GetFieldDef(); @@ -3091,18 +3091,15 @@ void BfIRBuilder::CreateDbgTypeDefinition(BfType* type) { staticValue = ConstToMemory(staticValue); wasMadeAddr = true; - } - else if (resolvedFieldType->IsPointer()) + } + else if (constant->mTypeCode == BfTypeCode_StringId) { int stringId = constant->mInt32; const StringImpl& str = mModule->mContext->mStringObjectIdMap[stringId].mString; - staticValue = mModule->GetStringCharPtr(str); - } - else if (constant->mTypeCode == BfTypeCode_StringId) - { - int stringId = constant->mInt32; - const StringImpl& str = mModule->mContext->mStringObjectIdMap[stringId].mString; - staticValue = mModule->GetStringObjectValue(str); + if (resolvedFieldType->IsPointer()) + staticValue = mModule->GetStringCharPtr(str); + else + staticValue = mModule->GetStringObjectValue(str); } else { From f92c3d14246243b79aa8596e9f967f553780dded Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 14 Dec 2021 09:54:22 -0500 Subject: [PATCH 027/139] Reduced _imp symbols for methods that may become unreified --- IDEHelper/Compiler/BfModule.cpp | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 855e958d..4e3c6563 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -16212,6 +16212,8 @@ void BfModule::EmitDtorBody() BfIRValue BfModule::CreateDllImportGlobalVar(BfMethodInstance* methodInstance, bool define) { + BF_ASSERT(methodInstance->mIsReified); + auto typeInstance = methodInstance->GetOwner(); bool foundDllImportAttr = false; @@ -22791,18 +22793,6 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool //BF_ASSERT(mCompiler->IsAutocomplete()); BfLogSysM("DoMethodDeclaration isTemporaryFunc bailout\n"); return; // Bail out early for autocomplete pass - } - - if ((methodInstance->GetImportCallKind() != BfImportCallKind_None) && (!mBfIRBuilder->mIgnoreWrites) && (!methodInstance->mIRFunction)) - { - BfLogSysM("DllImportGlobalVar DoMethodDeclaration processing %p\n", methodInstance); - // If this is in an extension then we did create the global variable already in the original obj - bool doDefine = mExtensionCount == 0; - BfIRValue dllImportGlobalVar = CreateDllImportGlobalVar(methodInstance, doDefine); - func = mBfIRBuilder->GetFakeVal(); - methodInstance->mIRFunction = func; - BF_ASSERT(dllImportGlobalVar); - mFuncReferences[mCurMethodInstance] = dllImportGlobalVar; } //TODO: We used to have this (this != mContext->mExternalFuncModule) check, but it caused us to keep around From a32dad3740f81a38c47d350e3cab78ed2e2628b1 Mon Sep 17 00:00:00 2001 From: disarray2077 <86157825+disarray2077@users.noreply.github.com> Date: Tue, 14 Dec 2021 12:21:53 -0300 Subject: [PATCH 028/139] Optimize the remove method of dictionary enumerator --- BeefLibs/corlib/src/Collections/Dictionary.bf | 43 +++++++++++++++++-- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/BeefLibs/corlib/src/Collections/Dictionary.bf b/BeefLibs/corlib/src/Collections/Dictionary.bf index 493a3309..1aaa7ccf 100644 --- a/BeefLibs/corlib/src/Collections/Dictionary.bf +++ b/BeefLibs/corlib/src/Collections/Dictionary.bf @@ -578,6 +578,43 @@ namespace System.Collections return oldPtr; } + private bool RemoveEntry(int32 hashCode, int_cosize index) + { + if (mBuckets != null) + { + int bucket = hashCode % (int_cosize)mAllocSize; + int lastIndex = -1; + + for (int_cosize i = mBuckets[bucket]; i >= 0; lastIndex = i, i = mEntries[i].mNext) + { + if (i == index) + { + if (lastIndex < 0) + { + mBuckets[bucket] = mEntries[index].mNext; + } + else + { + mEntries[lastIndex].mNext = mEntries[index].mNext; + } + mEntries[index].mHashCode = -1; + mEntries[index].mNext = mFreeList; +#if BF_ENABLE_REALTIME_LEAK_CHECK + mEntries[index].mKey = default; + mEntries[index].mValue = default; +#endif + mFreeList = index; + mFreeCount++; +#if VERSION_DICTIONARY + mVersion++; +#endif + return true; + } + } + } + return false; + } + public bool Remove(TKey key) { if (mBuckets != null) @@ -901,7 +938,7 @@ namespace System.Collections public void Remove() mut { int_cosize curIdx = mIndex - 1; - mDictionary.Remove(mDictionary.mEntries[curIdx].mKey); + mDictionary.RemoveEntry(mDictionary.mEntries[curIdx].mHashCode, curIdx); #if VERSION_DICTIONARY mVersion = mDictionary.mVersion; #endif @@ -1052,7 +1089,7 @@ namespace System.Collections public void Remove() mut { int_cosize curIdx = mIndex - 1; - mDictionary.Remove(mDictionary.mEntries[curIdx].mKey); + mDictionary.RemoveEntry(mDictionary.mEntries[curIdx].mHashCode, curIdx); #if VERSION_DICTIONARY mVersion = mDictionary.mVersion; #endif @@ -1158,7 +1195,7 @@ namespace System.Collections public void Remove() mut { int_cosize curIdx = mIndex - 1; - mDictionary.Remove(mDictionary.mEntries[curIdx].mKey); + mDictionary.RemoveEntry(mDictionary.mEntries[curIdx].mHashCode, curIdx); #if VERSION_DICTIONARY mVersion = mDictionary.mVersion; #endif From 5c08c3716c69a890ad2202dd76e15e7804ddf460 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 14 Dec 2021 10:46:27 -0500 Subject: [PATCH 029/139] Invalid assert removed --- IDEHelper/Backend/BeCOFFObject.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/IDEHelper/Backend/BeCOFFObject.cpp b/IDEHelper/Backend/BeCOFFObject.cpp index 5456c395..7dffb212 100644 --- a/IDEHelper/Backend/BeCOFFObject.cpp +++ b/IDEHelper/Backend/BeCOFFObject.cpp @@ -1019,8 +1019,7 @@ void BeCOFFObject::DbgStartSection(int sectionNum) void BeCOFFObject::DbgEndSection() { auto& outS = mDebugSSect.mData; - int totalLen = outS.GetPos() - mSectionStartPos; - BF_ASSERT(totalLen <= 0xFFFF); + int totalLen = outS.GetPos() - mSectionStartPos; *((int32*)&outS.mData[mSectionStartPos - 4]) = totalLen; mSectionStartPos = -1; while ((outS.GetPos() & 3) != 0) From 8623f8f7e5581da85300bb4716efb65c868a8428 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 14 Dec 2021 11:13:51 -0500 Subject: [PATCH 030/139] Removed buttons during regen --- BeefLibs/corlib/src/Compiler.bf | 1 + IDE/src/ui/GenerateDialog.bf | 30 +++++++++++++++++++++--------- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/BeefLibs/corlib/src/Compiler.bf b/BeefLibs/corlib/src/Compiler.bf index ff90fc24..eb6c130c 100644 --- a/BeefLibs/corlib/src/Compiler.bf +++ b/BeefLibs/corlib/src/Compiler.bf @@ -27,6 +27,7 @@ namespace System public StringView WorkspaceName => mParams["WorkspaceName"]; public StringView WorkspaceDir => mParams["WorkspaceDir"]; public StringView DateTime => mParams["DateTime"]; + public bool IsRegenererating => mParams.GetValueOrDefault("Regenerating") == "True"; public void Fail(StringView error) { diff --git a/IDE/src/ui/GenerateDialog.bf b/IDE/src/ui/GenerateDialog.bf index bd870f94..67c2624c 100644 --- a/IDE/src/ui/GenerateDialog.bf +++ b/IDE/src/ui/GenerateDialog.bf @@ -256,11 +256,14 @@ namespace IDE.ui mWindowFlags = .ClientSized | .TopMost | .Caption | .Border | .SysMenu | .Resizable | .PopupPosition; - AddOkCancelButtons(new (evt) => - { - Submit(); - evt.mCloseDialog = false; - }, null, 0, 1); + if (!mRegenerating) + { + AddOkCancelButtons(new (evt) => + { + Submit(); + evt.mCloseDialog = false; + }, null, 0, 1); + } Title = "Generate File"; @@ -399,6 +402,9 @@ namespace IDE.ui return; using (gApp.mMonitor.Enter()) { + if (mRegenerating) + args.Append("Regenerating\tTrue\n"); + args.AppendF( $""" ProjectName\t{mProjectName} @@ -496,6 +502,7 @@ namespace IDE.ui { if (mOutputPanel == null) { + IDEApp.Beep(.Error); mOutputPanel = new OutputPanel(); AddWidget(mOutputPanel); ResizeComponents(); @@ -677,6 +684,11 @@ namespace IDE.ui Close(); } + if ((hadError) && (mRegenerating) && (mOutputPanel == null)) + { + Close(); + } + if (mPendingUIFocus) { mPendingUIFocus = false; @@ -695,8 +707,8 @@ namespace IDE.ui { mSubmitting = false; mSubmitQueued = false; - mDefaultButton.mDisabled = false; - mEscButton.mDisabled = false; + mDefaultButton?.mDisabled = false; + mEscButton?.mDisabled = false; } } else @@ -802,7 +814,7 @@ namespace IDE.ui if (mThreadWaitCount > 10) { using (g.PushColor(0x60505050)) - g.FillRect(0, 0, mWidth, mHeight - GS!(40)); + g.FillRect(0, 0, mWidth, mHeight - ((mDefaultButton != null) ? GS!(40) : GS!(0))); IDEUtils.DrawWait(g, mWidth/2, mHeight/2, mUpdateCnt); } } @@ -840,7 +852,7 @@ namespace IDE.ui 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))); + mOutputPanel.Resize(insetSize, startY, mWidth - insetSize - insetSize, Math.Max(mHeight - startY - ((mDefaultButton != null) ? GS!(44) : GS!(12)), GS!(32))); mUIHeight = Math.Max(mUIHeight, GS!(160)); } } From f85a4317fc13b6a8104162305b52d1c35e46eb66 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 14 Dec 2021 11:26:24 -0500 Subject: [PATCH 031/139] Fixed invalid underlying enum type error --- IDEHelper/Compiler/BfModuleTypeUtils.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 81db527c..d538f162 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -2927,6 +2927,9 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy { bool hadType = false; + BfAstNode* deferredErrorNode = NULL; + char* deferredError = NULL; + for (auto baseTypeRef : typeDef->mBaseTypes) { SetAndRestoreValue prevTypeRef(mContext->mCurTypeState->mCurBaseTypeRef, baseTypeRef); @@ -2946,12 +2949,14 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy } else { - Fail("Underlying enum type already specified", baseTypeRef); + deferredError = "Underlying enum type already specified"; + deferredErrorNode = baseTypeRef; } } else { - Fail("Invalid underlying enum type", baseTypeRef); + deferredError = "Invalid underlying enum type"; + deferredErrorNode = baseTypeRef; } } else @@ -2961,6 +2966,9 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy } } + if (deferredError != NULL) + Fail(deferredError, deferredErrorNode, true); + if (underlyingType == NULL) { underlyingType = GetPrimitiveType(BfTypeCode_Int64); From fd098f3e96494a192e357e5a9c644659d81e3a74 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 14 Dec 2021 11:41:11 -0500 Subject: [PATCH 032/139] Removed 'comptime evaluation canceled' error --- IDEHelper/Compiler/CeMachine.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/IDEHelper/Compiler/CeMachine.cpp b/IDEHelper/Compiler/CeMachine.cpp index 4a843de2..579630e3 100644 --- a/IDEHelper/Compiler/CeMachine.cpp +++ b/IDEHelper/Compiler/CeMachine.cpp @@ -4983,7 +4983,12 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* if (*fastFinishPtr) { if (*cancelingPtr) - _Fail("Comptime evaluation canceled"); + { + if ((mCurModule != NULL) && (mCurModule->mCurTypeInstance != NULL)) + mCurModule->DeferRebuildType(mCurModule->mCurTypeInstance); + else + _Fail("Comptime evaluation canceled"); + } return false; } From c59fac571a7e02d78ffaff9e2df82334f262329f Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 14 Dec 2021 12:35:42 -0500 Subject: [PATCH 033/139] Fixed issue with ref to an opaque type --- IDEHelper/Compiler/BfModule.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 4e3c6563..0036da17 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -16478,7 +16478,7 @@ void BfModule::SetupIRMethod(BfMethodInstance* methodInstance, BfIRFunction func auto elementType = refType->mElementType; PopulateType(elementType, BfPopulateType_Data); addDeref = elementType->mSize; - if ((addDeref <= 0) && (!elementType->IsValuelessType())) + if ((addDeref <= 0) && (!elementType->IsValuelessType()) && (!elementType->IsOpaque())) AssertErrorState(); } if ((resolvedTypeRef->IsComposite()) && (!resolvedTypeRef->IsTypedPrimitive())) From 4d337e3a31283b264db317745116ed0e94bbb891 Mon Sep 17 00:00:00 2001 From: disarray2077 <86157825+disarray2077@users.noreply.github.com> Date: Tue, 14 Dec 2021 16:25:39 -0300 Subject: [PATCH 034/139] Fix dialogs in release mode ... and inline "GetFilterItems" method so we can use scoped allocation --- BeefLibs/corlib/src/IO/FileDialog.Vista.bf | 61 +++++++--------------- BeefLibs/corlib/src/IO/OpenFileDialog.bf | 9 ++-- BeefLibs/corlib/src/IO/SaveFileDialog.bf | 3 +- 3 files changed, 28 insertions(+), 45 deletions(-) diff --git a/BeefLibs/corlib/src/IO/FileDialog.Vista.bf b/BeefLibs/corlib/src/IO/FileDialog.Vista.bf index 994a2382..2bef240c 100644 --- a/BeefLibs/corlib/src/IO/FileDialog.Vista.bf +++ b/BeefLibs/corlib/src/IO/FileDialog.Vista.bf @@ -99,20 +99,30 @@ namespace System.IO private Result SetFileTypes(Windows.COM_IFileDialog* dialog) { List filterItems = scope .(); - GetFilterItems(filterItems, mFilter); - if (filterItems.Count == 0) - return .Ok; - - defer + // Expected input types + // "Text files (*.txt)|*.txt|All files (*.*)|*.*" + // "Image Files(*.BMP;*.JPG;*.GIF)|*.BMP;*.JPG;*.GIF|All files (*.*)|*.*" + if (!String.IsNullOrEmpty(mFilter)) { - for (var filter in filterItems) - { - delete filter.pszName; - delete filter.pszSpec; - } + StringView[] tokens = mFilter.Split!('|'); + if (0 == tokens.Count % 2) + { + // All even numbered tokens should be labels + // Odd numbered tokens are the associated extensions + for (int i = 1; i < tokens.Count; i += 2) + { + Windows.COMDLG_FILTERSPEC ext; + ext.pszSpec = tokens[i].ToScopedNativeWChar!::(); // This may be a semicolon delimited list of extensions (that's ok) + ext.pszName = tokens[i - 1].ToScopedNativeWChar!::(); + filterItems.Add(ext); + } + } } + if (filterItems.IsEmpty) + return .Ok; + Windows.COM_IUnknown.HResult hr = dialog.VT.SetFileTypes(dialog, (uint32)filterItems.Count, filterItems.Ptr); if (hr.Failed) return .Err; @@ -123,37 +133,6 @@ namespace System.IO return .Ok; } - - private static void GetFilterItems(List list, String filter) - { - mixin ToHeapWChar(var str) - { - int encodedLen = System.Text.UTF16.GetEncodedLen(str); - char16* buf = new char16[encodedLen]* ( ? ); - System.Text.UTF16.Encode(str, buf, encodedLen); - buf - } - - // Expected input types - // "Text files (*.txt)|*.txt|All files (*.*)|*.*" - // "Image Files(*.BMP;*.JPG;*.GIF)|*.BMP;*.JPG;*.GIF|All files (*.*)|*.*" - if (!String.IsNullOrEmpty(filter)) - { - StringView[] tokens = filter.Split!('|'); - if (0 == tokens.Count % 2) - { - // All even numbered tokens should be labels - // Odd numbered tokens are the associated extensions - for (int i = 1; i < tokens.Count; i += 2) - { - Windows.COMDLG_FILTERSPEC ext; - ext.pszSpec = ToHeapWChar!(tokens[i]); // This may be a semicolon delimited list of extensions (that's ok) - ext.pszName = ToHeapWChar!(tokens[i - 1]); - list.Add(ext); - } - } - } - } } } #endif \ No newline at end of file diff --git a/BeefLibs/corlib/src/IO/OpenFileDialog.bf b/BeefLibs/corlib/src/IO/OpenFileDialog.bf index 6523c097..c7c79d11 100644 --- a/BeefLibs/corlib/src/IO/OpenFileDialog.bf +++ b/BeefLibs/corlib/src/IO/OpenFileDialog.bf @@ -120,14 +120,16 @@ namespace System.IO Windows.COM_IFileOpenDialog* openDialog = (.)dialog; if (Multiselect) { - openDialog.VT.GetResults(openDialog, let results); + Windows.COM_IShellItemArray* results = null; + openDialog.VT.GetResults(openDialog, out results); if (results != null) { results.VT.GetCount(results, let count); for (uint32 i < count) { - results.VT.GetItemAt(results, i, let item); + Windows.COM_IShellItem* item = null; + results.VT.GetItemAt(results, i, out item); if (item != null) { let filePath = GetFilePathFromShellItem!(item); @@ -140,7 +142,8 @@ namespace System.IO } else { - openDialog.VT.GetResult(openDialog, let shellItem); + Windows.COM_IShellItem* shellItem = null; + openDialog.VT.GetResult(openDialog, out shellItem); if (shellItem != null) { diff --git a/BeefLibs/corlib/src/IO/SaveFileDialog.bf b/BeefLibs/corlib/src/IO/SaveFileDialog.bf index 19064fbc..58e1bca9 100644 --- a/BeefLibs/corlib/src/IO/SaveFileDialog.bf +++ b/BeefLibs/corlib/src/IO/SaveFileDialog.bf @@ -109,7 +109,8 @@ namespace System.IO } Windows.COM_IFileSaveDialog* saveDialog = (.)dialog; - saveDialog.VT.GetResult(saveDialog, let shellItem); + Windows.COM_IShellItem* shellItem = null; + saveDialog.VT.GetResult(saveDialog, out shellItem); if (shellItem != null) { From 798c259e53a34401f92fe224cefb85831424ff9c Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 14 Dec 2021 14:33:12 -0500 Subject: [PATCH 035/139] Spelling fix --- BeefLibs/corlib/src/Compiler.bf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BeefLibs/corlib/src/Compiler.bf b/BeefLibs/corlib/src/Compiler.bf index eb6c130c..cb706d01 100644 --- a/BeefLibs/corlib/src/Compiler.bf +++ b/BeefLibs/corlib/src/Compiler.bf @@ -27,7 +27,7 @@ namespace System public StringView WorkspaceName => mParams["WorkspaceName"]; public StringView WorkspaceDir => mParams["WorkspaceDir"]; public StringView DateTime => mParams["DateTime"]; - public bool IsRegenererating => mParams.GetValueOrDefault("Regenerating") == "True"; + public bool IsRegenerating => mParams.GetValueOrDefault("Regenerating") == "True"; public void Fail(StringView error) { From bb6c59e39ea093d3bd09b4e2c8abb643512431d0 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Wed, 15 Dec 2021 08:42:11 -0500 Subject: [PATCH 036/139] Disallowed cast from func constraint to void* or delegate to object --- IDEHelper/Compiler/BfModuleTypeUtils.cpp | 42 ++++++++++++++---------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index d538f162..79ed59ae 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -11513,29 +11513,37 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp { SetAndRestoreValue prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, true); auto constraintTypeInst = genericParamInst->mTypeConstraint->ToTypeInstance(); - if ((constraintTypeInst != NULL) && (constraintTypeInst->IsInstanceOf(mCompiler->mEnumTypeDef)) && (explicitCast)) + + if ((constraintTypeInst != NULL) && (constraintTypeInst->IsDelegateOrFunction())) { - // Enum->int - if ((explicitCast) && (toType->IsInteger())) - return typedVal.mValue; + // Could be a methodref - can't cast to anything else } - - BfTypedValue fromTypedValue; - if (typedVal.mKind == BfTypedValueKind_GenericConstValue) - fromTypedValue = GetDefaultTypedValue(genericParamInst->mTypeConstraint, false, BfDefaultValueKind_Undef); else - fromTypedValue = BfTypedValue(mBfIRBuilder->GetFakeVal(), genericParamInst->mTypeConstraint, genericParamInst->mTypeConstraint->IsValueType()); - - auto result = CastToValue(srcNode, fromTypedValue, toType, (BfCastFlags)(castFlags | BfCastFlags_SilentFail)); - if (result) { - if ((genericParamInst->mTypeConstraint->IsDelegate()) && (toType->IsDelegate())) + if ((constraintTypeInst != NULL) && (constraintTypeInst->IsInstanceOf(mCompiler->mEnumTypeDef)) && (explicitCast)) { - // Don't allow cast when we are constrained by a delegate type, because BfMethodRefs can match and we require an actual alloc - Fail(StrFormat("Unable to cast '%s' to '%s' because delegate constraints allow valueless direct method references", TypeToString(typedVal.mType).c_str(), TypeToString(toType).c_str()), srcNode); - return BfIRValue(); + // Enum->int + if ((explicitCast) && (toType->IsInteger())) + return typedVal.mValue; + } + + BfTypedValue fromTypedValue; + if (typedVal.mKind == BfTypedValueKind_GenericConstValue) + fromTypedValue = GetDefaultTypedValue(genericParamInst->mTypeConstraint, false, BfDefaultValueKind_Undef); + else + fromTypedValue = BfTypedValue(mBfIRBuilder->GetFakeVal(), genericParamInst->mTypeConstraint, genericParamInst->mTypeConstraint->IsValueType()); + + auto result = CastToValue(srcNode, fromTypedValue, toType, (BfCastFlags)(castFlags | BfCastFlags_SilentFail)); + if (result) + { + if ((genericParamInst->mTypeConstraint->IsDelegate()) && (toType->IsDelegate())) + { + // Don't allow cast when we are constrained by a delegate type, because BfMethodRefs can match and we require an actual alloc + Fail(StrFormat("Unable to cast '%s' to '%s' because delegate constraints allow valueless direct method references", TypeToString(typedVal.mType).c_str(), TypeToString(toType).c_str()), srcNode); + return BfIRValue(); + } + return result; } - return result; } } From 53312a35f35c522a856059a6b7c94d2f2070f8b6 Mon Sep 17 00:00:00 2001 From: disarray2077 <86157825+disarray2077@users.noreply.github.com> Date: Wed, 15 Dec 2021 11:41:02 -0300 Subject: [PATCH 037/139] Allow underline in generated file name --- IDE/src/ui/GenerateDialog.bf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IDE/src/ui/GenerateDialog.bf b/IDE/src/ui/GenerateDialog.bf index 67c2624c..7bb15545 100644 --- a/IDE/src/ui/GenerateDialog.bf +++ b/IDE/src/ui/GenerateDialog.bf @@ -653,7 +653,7 @@ namespace IDE.ui { for (char8 c in fileName.RawChars) { - if (!c.IsLetterOrDigit) + if (!c.IsLetterOrDigit && c != '_') { gApp.Fail(scope $"Invalid generated file name: {fileName}"); hadError = true; From 6a95cbb3b8af31457170983345978ae52f6e6a41 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Wed, 15 Dec 2021 10:48:42 -0500 Subject: [PATCH 038/139] Diallow mut mismatch on function bind --- IDEHelper/Compiler/BfExprEvaluator.cpp | 22 ++++++++++++++-------- IDEHelper/Compiler/BfModule.cpp | 12 ++++++++++-- IDEHelper/Compiler/BfResolvedTypeUtils.cpp | 9 --------- IDEHelper/Compiler/BfResolvedTypeUtils.h | 3 ++- 4 files changed, 26 insertions(+), 20 deletions(-) diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index e36dc52f..5f40ac99 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -11140,8 +11140,7 @@ void BfExprEvaluator::Visit(BfCastExpression* castExpr) bool BfExprEvaluator::IsExactMethodMatch(BfMethodInstance* methodA, BfMethodInstance* methodB, bool ignoreImplicitParams) { if (methodA->mReturnType != methodB->mReturnType) - return false; - + return false; int implicitParamCountA = methodA->GetImplicitParamCount(); if (methodA->HasExplicitThis()) implicitParamCountA++; @@ -11703,7 +11702,11 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr) } else { - if (!IsExactMethodMatch(methodInstance, bindMethodInstance, true)) + bool isExactMethodMatch = IsExactMethodMatch(methodInstance, bindMethodInstance, true); + if ((mExpectingType != NULL) && (mExpectingType->IsFunction()) && (methodInstance->mMethodDef->mIsMutating != bindMethodInstance->mMethodDef->mIsMutating)) + isExactMethodMatch = false; + + if (!isExactMethodMatch) { if (bindResult.mCheckedMultipleMethods) { @@ -11711,8 +11714,8 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr) mModule->TypeToString(delegateTypeInstance).c_str()), delegateBindExpr->mTarget); } else - { - mModule->Fail(StrFormat("Method '%s' does not match %s '%s'", mModule->MethodToString(bindMethodInstance).c_str(), bindTypeName, + { + mModule->Fail(StrFormat("Method '%s' does not match %s '%s'", mModule->MethodToString(bindMethodInstance, (BfMethodNameFlags)(BfMethodNameFlag_IncludeReturnType | BfMethodNameFlag_IncludeMut)).c_str(), bindTypeName, mModule->TypeToString(delegateTypeInstance).c_str()), delegateBindExpr->mTarget); } mResult = BfTypedValue(); @@ -11732,7 +11735,7 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr) } bool hasIncompatibleCallingConventions = !mModule->mSystem->IsCompatibleCallingConvention(methodInstance->mCallingConvention, bindMethodInstance->mCallingConvention); - + auto _GetInvokeMethodName = [&]() { String methodName = "Invoke$"; @@ -11806,11 +11809,14 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr) if (result) { - String methodName = _GetInvokeMethodName(); + String methodName = _GetInvokeMethodName(); SizedArray irParamTypes; BfIRType irReturnType; - bindMethodInstance->GetIRFunctionInfo(mModule, irReturnType, irParamTypes); + methodInstance->GetIRFunctionInfo(mModule, irReturnType, irParamTypes); + + int thisFuncParamIdx = methodInstance->GetThisIdx(); + int thisBindParamIdx = methodInstance->GetThisIdx(); auto prevActiveFunction = mModule->mBfIRBuilder->GetActiveFunction(); auto prevInsertBlock = mModule->mBfIRBuilder->GetInsertBlock(); diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 0036da17..1d8a28b2 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -10524,7 +10524,7 @@ bool BfModule::HasMixin(BfTypeInstance* typeInstance, const StringImpl& methodNa } StringT<128> BfModule::MethodToString(BfMethodInstance* methodInst, BfMethodNameFlags methodNameFlags, BfTypeVector* typeGenericArgs, BfTypeVector* methodGenericArgs) -{ +{ auto methodDef = methodInst->mMethodDef; bool allowResolveGenericParamNames = ((methodNameFlags & BfMethodNameFlag_ResolveGenericParamNames) != 0); @@ -10769,8 +10769,16 @@ StringT<128> BfModule::MethodToString(BfMethodInstance* methodInst, BfMethodName if (accessorString.length() != 0) { - methodName += " " + accessorString; + methodName += " "; + methodName += accessorString; } + + if ((methodNameFlags & BfMethodNameFlag_IncludeMut) != 0) + { + if ((methodDef->mIsMutating) && (methodInst->GetOwner()->IsValueType())) + methodName += " mut"; + } + return methodName; } diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp index 7b85a000..c99a4e77 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp @@ -1298,15 +1298,6 @@ void BfMethodInstance::GetIRFunctionInfo(BfModule* module, BfIRType& returnType, } } -// if ((paramIdx == 0) && (GetParamName(0) == "this") && (checkType->IsPointer())) -// { -// // We don't actually pass a this pointer for mut methods in valueless structs -// auto underlyingType = checkType->GetUnderlyingType(); -// module->PopulateType(underlyingType, BfPopulateType_Data); -// if (underlyingType->IsValuelessType()) -// continue; -// } - if (checkType->CanBeValuelessType()) module->PopulateType(checkType, BfPopulateType_Data); if ((checkType->IsValuelessType()) && (!checkType->IsMethodRef())) diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index 0f7a6fa9..7563609d 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -61,7 +61,8 @@ enum BfMethodNameFlags : uint8 BfMethodNameFlag_ResolveGenericParamNames = 1, BfMethodNameFlag_OmitTypeName = 2, BfMethodNameFlag_IncludeReturnType = 4, - BfMethodNameFlag_OmitParams = 8 + BfMethodNameFlag_OmitParams = 8, + BfMethodNameFlag_IncludeMut = 0x10 }; enum BfGetMethodInstanceFlags : uint16 From a3b761ab266f13292cd067abf3b10a091c4ff392 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Wed, 15 Dec 2021 12:17:20 -0500 Subject: [PATCH 039/139] Fixes for literal overflow detection --- IDEHelper/Compiler/BfExprEvaluator.cpp | 2 +- IDEHelper/Compiler/BfModule.cpp | 2 +- IDEHelper/Compiler/BfParser.cpp | 66 +++++++++++--------------- IDEHelper/Compiler/BfParser.h | 1 + IDEHelper/Compiler/BfSystem.cpp | 35 ++++++++++++++ IDEHelper/Compiler/BfSystem.h | 1 + 6 files changed, 68 insertions(+), 39 deletions(-) diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 5f40ac99..7ab34ee4 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -3578,7 +3578,7 @@ void BfExprEvaluator::GetLiteral(BfAstNode* refNode, const BfVariant& variant) if ((mExpectingType != NULL) && (mExpectingType->IsIntegral()) && (mExpectingType->IsChar() == IsCharType(variant.mTypeCode))) { auto primType = (BfPrimitiveType*)mExpectingType; - if (mModule->mSystem->DoesLiteralFit(primType->mTypeDef->mTypeCode, variant.mInt64)) + if (mModule->mSystem->DoesLiteralFit(primType->mTypeDef->mTypeCode, variant.mUInt64)) { mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConst(primType->mTypeDef->mTypeCode, variant.mUInt64), mExpectingType); break; diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 1d8a28b2..17fb80af 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -7889,7 +7889,7 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS { if (BfIRConstHolder::IsInt(primType->mTypeDef->mTypeCode)) { - if (!mCompiler->mSystem->DoesLiteralFit(primType->mTypeDef->mTypeCode, constExprValueType->mValue.mInt64)) + if (!mCompiler->mSystem->DoesLiteralFit(primType->mTypeDef->mTypeCode, constExprValueType->mValue.mUInt64)) { if ((!ignoreErrors) && (PreFail())) *errorOut = Fail(StrFormat("Const generic argument '%s', declared with const '%lld', does not fit into const constraint '%s' for '%s'", genericParamInst->GetName().c_str(), diff --git a/IDEHelper/Compiler/BfParser.cpp b/IDEHelper/Compiler/BfParser.cpp index dce0e396..e96ba38f 100644 --- a/IDEHelper/Compiler/BfParser.cpp +++ b/IDEHelper/Compiler/BfParser.cpp @@ -2447,10 +2447,9 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate) mTokenEnd = mSrcIdx; return; } - - bool wasNeg = false; + bool hadOverflow = false; - int64 val = 0; + uint64 val = 0; int numberBase = 10; int expVal = 0; int expSign = 0; @@ -2460,8 +2459,7 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate) int hexDigits = 0; if (c == '-') { - wasNeg = true; //TODO: This never actually gets set any more (eaten as BfToken_Minus above). Move checks that use this to later in pipeline, then remove this - c = mSrc[mSrcIdx++]; + BF_FATAL("Parsing error"); } val = c - '0'; @@ -2641,7 +2639,7 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate) // This is actually a integer followed by an Int32 call (like 123.ToString) mSrcIdx -= 2; mTokenEnd = mSrcIdx; - mLiteral.mInt64 = val; + mLiteral.mUInt64 = val; mLiteral.mTypeCode = BfTypeCode_IntUnknown; mSyntaxToken = BfSyntaxToken_Literal; return; @@ -2668,27 +2666,24 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate) if (endNumber) { mTokenEnd = mSrcIdx - 1; - mSrcIdx--; - if (wasNeg) - val = -val; + mSrcIdx--; if ((numberBase == 0x10) && ((hexDigits >= 16) || ((hadSeps) && (hexDigits > 8)) || ((hadLeadingHexSep) && (hexDigits == 8)))) { if (hexDigits > 16) mPassInstance->FailAt("Too many hex digits for int64", mSourceData, mTokenStart, mSrcIdx - mTokenStart); - mLiteral.mInt64 = val; - if ((val < 0) && (!wasNeg)) + mLiteral.mUInt64 = val; + if (val >= 0x8000000000000000) mLiteral.mTypeCode = BfTypeCode_UInt64; else mLiteral.mTypeCode = BfTypeCode_Int64; } else { - mLiteral.mInt64 = val; + mLiteral.mUInt64 = val; mLiteral.mTypeCode = BfTypeCode_IntUnknown; - if ((numberBase == 0x10) && (hexDigits == 7)) mLiteral.mWarnType = BfWarning_BF4201_Only7Hex; if ((numberBase == 0x10) && (hexDigits == 9)) @@ -2699,7 +2694,12 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate) mPassInstance->FailAt("Value doesn't fit into int64", mSourceData, mTokenStart, mSrcIdx - mTokenStart); mLiteral.mTypeCode = BfTypeCode_Int64; } - else if ((val < -0x80000000LL) || (val > 0xFFFFFFFFLL)) + //else if ((val < -0x80000000LL) || (val > 0xFFFFFFFFLL)) + else if (val >= 0x8000000000000000) + { + mLiteral.mTypeCode = BfTypeCode_UInt64; + } + else if (val > 0xFFFFFFFFLL) { mLiteral.mTypeCode = BfTypeCode_Int64; } @@ -2709,7 +2709,7 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate) return; } - int64 prevVal = val; + uint64 prevVal = val; if ((c >= '0') && (c <= '9') && (c < '0' + numberBase)) { if (numberBase == 0x10) @@ -2731,9 +2731,7 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate) } else if ((c == 'u') || (c == 'U')) - { - if (wasNeg) - val = -val; + { if ((mSrc[mSrcIdx] == 'l') || (mSrc[mSrcIdx] == 'L')) { if (mSrc[mSrcIdx] == 'l') @@ -2744,7 +2742,7 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate) mLiteral.mUInt64 = (uint64)val; if (hexDigits > 16) mPassInstance->FailAt("Too many hex digits for int64", mSourceData, mTokenStart, mSrcIdx - mTokenStart); - else if ((hadOverflow) || (wasNeg)) + else if (hadOverflow) mPassInstance->FailAt("Value doesn't fit into uint64", mSourceData, mTokenStart, mSrcIdx - mTokenStart); mSyntaxToken = BfSyntaxToken_Literal; return; @@ -2752,7 +2750,7 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate) mTokenEnd = mSrcIdx; mLiteral.mTypeCode = BfTypeCode_UIntPtr; mLiteral.mUInt32 = (uint32)val; - if ((hadOverflow) || (wasNeg) || ((uint64)val != (uint64)mLiteral.mUInt32)) + if ((hadOverflow) || ((uint64)val != (uint64)mLiteral.mUInt32)) mPassInstance->FailAt("Value doesn't fit into uint32", mSourceData, mTokenStart, mSrcIdx - mTokenStart); mSyntaxToken = BfSyntaxToken_Literal; return; @@ -2760,9 +2758,7 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate) else if ((c == 'l') || (c == 'L')) { if (c == 'l') - TokenFail("Uppercase 'L' required for int64"); - if (wasNeg) - val = -val; + TokenFail("Uppercase 'L' required for int64"); if ((mSrc[mSrcIdx] == 'u') || (mSrc[mSrcIdx] == 'U')) { mSrcIdx++; @@ -2771,25 +2767,24 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate) mLiteral.mUInt64 = (uint64)val; if (hexDigits > 16) mPassInstance->FailAt("Too many hex digits for int64", mSourceData, mTokenStart, mSrcIdx - mTokenStart); - else if ((hadOverflow) || (wasNeg)) + else if (hadOverflow) mPassInstance->FailAt("Value doesn't fit into uint64", mSourceData, mTokenStart, mSrcIdx - mTokenStart); mSyntaxToken = BfSyntaxToken_Literal; return; - } + } mTokenEnd = mSrcIdx; mLiteral.mTypeCode = BfTypeCode_Int64; mLiteral.mInt64 = (int64)val; - - bool signMatched = true; - if (val != 0) - signMatched = (val < 0) == wasNeg; - + if (val == 0x8000000000000000) + mLiteral.mTypeCode = BfTypeCode_UInt64; + else if (val >= 0x8000000000000000) + hadOverflow = true; if (numberBase == 0x10) { if (hexDigits > 16) mPassInstance->FailAt("Too many hex digits for int64", mSourceData, mTokenStart, mSrcIdx - mTokenStart); } - else if ((hadOverflow) || (!signMatched)) + else if (hadOverflow) mPassInstance->FailAt("Value doesn't fit into int64", mSourceData, mTokenStart, mSrcIdx - mTokenStart); mSyntaxToken = BfSyntaxToken_Literal; return; @@ -2813,17 +2808,14 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate) else { mTokenEnd = mSrcIdx - 1; - mSrcIdx--; - if (wasNeg) - val = -val; - mLiteral.mInt64 = val; + mSrcIdx--; + mLiteral.mUInt64 = val; mLiteral.mTypeCode = BfTypeCode_IntUnknown; mSyntaxToken = BfSyntaxToken_Literal; TokenFail("Unexpected character while parsing number", 0); return; } - - //if ((val < 0) && (val != -0x8000000000000000)) + if ((uint64)prevVal > (uint64)val) hadOverflow = true; } diff --git a/IDEHelper/Compiler/BfParser.h b/IDEHelper/Compiler/BfParser.h index cc9a27ed..3c95ed8d 100644 --- a/IDEHelper/Compiler/BfParser.h +++ b/IDEHelper/Compiler/BfParser.h @@ -226,6 +226,7 @@ public: void SetSource(const char* data, int length); void MoveSource(const char* data, int length); // Takes ownership of data ptr void RefSource(const char* data, int length); + void MakeNegative(uint64& val, bool& hadOverflow); void NextToken(int endIdx = -1, bool outerIsInterpolate = false); BfAstNode* CreateNode(); diff --git a/IDEHelper/Compiler/BfSystem.cpp b/IDEHelper/Compiler/BfSystem.cpp index 4ff7e3d1..0f0419bd 100644 --- a/IDEHelper/Compiler/BfSystem.cpp +++ b/IDEHelper/Compiler/BfSystem.cpp @@ -2282,6 +2282,41 @@ bool BfSystem::DoesLiteralFit(BfTypeCode typeCode, int64 value) return false; } +bool BfSystem::DoesLiteralFit(BfTypeCode typeCode, uint64 value) +{ + if (typeCode == BfTypeCode_IntPtr) + typeCode = (mPtrSize == 4) ? BfTypeCode_Int32 : BfTypeCode_Int64; + if (typeCode == BfTypeCode_UIntPtr) + typeCode = (mPtrSize == 4) ? BfTypeCode_UInt32 : BfTypeCode_UInt64; + + if (value >= 0x8000000000000000) + return typeCode == BfTypeCode_UInt64; + + switch (typeCode) + { + case BfTypeCode_Int8: + return (value < 0x80); + case BfTypeCode_Int16: + return (value < 0x8000); + case BfTypeCode_Int32: + return (value < 0x80000000LL); + case BfTypeCode_Int64: + return true; + + case BfTypeCode_UInt8: + return (value < 0x100); + case BfTypeCode_UInt16: + return (value < 0x10000); + case BfTypeCode_UInt32: + return (value < 0x100000000LL); + case BfTypeCode_UInt64: + return true; + default: break; + } + + return false; +} + BfParser* BfSystem::CreateParser(BfProject* bfProject) { AutoCrit crit(mDataLock); diff --git a/IDEHelper/Compiler/BfSystem.h b/IDEHelper/Compiler/BfSystem.h index 42a35340..1a4fbd93 100644 --- a/IDEHelper/Compiler/BfSystem.h +++ b/IDEHelper/Compiler/BfSystem.h @@ -1610,6 +1610,7 @@ public: void CreateBasicTypes(); bool DoesLiteralFit(BfTypeCode typeCode, int64 value); + bool DoesLiteralFit(BfTypeCode typeCode, uint64 value); BfParser* CreateParser(BfProject* bfProject); BfCompiler* CreateCompiler(bool isResolveOnly); BfProject* GetProject(const StringImpl& projName); From ae186433cc1b1452b1964e657b81a1f05c2ade71 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Wed, 15 Dec 2021 14:41:30 -0500 Subject: [PATCH 040/139] Negative zero fix --- BeefLibs/corlib/src/Double.bf | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/BeefLibs/corlib/src/Double.bf b/BeefLibs/corlib/src/Double.bf index 63176ab3..5c75b453 100644 --- a/BeefLibs/corlib/src/Double.bf +++ b/BeefLibs/corlib/src/Double.bf @@ -21,8 +21,7 @@ namespace System public const double NegativeInfinity = (double)(- 1.0 / (double)(0.0)); public const double PositiveInfinity = (double)1.0 / (double)(0.0); public const double NaN = (double)0.0 / (double)0.0; - - static double NegativeZero = BitConverter.Convert(0x8000000000000000UL); + public const double NegativeZero = -0.0; public static int operator<=>(Double a, Double b) { From a2a97a8e5fc745ea0f43f9f4e3854b0695b6fa0a Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Wed, 15 Dec 2021 16:24:30 -0500 Subject: [PATCH 041/139] Fixed issue detaching editdata when resetting ui --- IDE/src/Project.bf | 7 ++++++- IDE/src/ui/SourceViewPanel.bf | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/IDE/src/Project.bf b/IDE/src/Project.bf index ce90f199..56922862 100644 --- a/IDE/src/Project.bf +++ b/IDE/src/Project.bf @@ -355,7 +355,7 @@ namespace IDE return .SimpleSource; } - public override void Dispose() + public void ClearEditData() { if (mEditData != null) { @@ -365,6 +365,11 @@ namespace IDE } } + public override void Dispose() + { + ClearEditData(); + } + public override void Detach() { Dispose(); diff --git a/IDE/src/ui/SourceViewPanel.bf b/IDE/src/ui/SourceViewPanel.bf index e94ca7d2..6e814b31 100644 --- a/IDE/src/ui/SourceViewPanel.bf +++ b/IDE/src/ui/SourceViewPanel.bf @@ -546,6 +546,11 @@ namespace IDE.ui public ~this() { + if (mProjectSource?.mEditData?.HasTextChanged() == true) + { + mProjectSource.ClearEditData(); + } + if (mInPostRemoveUpdatePanels) { //Debug.WriteLine("Removing sourceViewPanel from mPostRemoveUpdatePanel {0} in ~this ", this); From ec8d666356d9e421220479fc88bbee34aef57087 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Wed, 15 Dec 2021 16:39:41 -0500 Subject: [PATCH 042/139] MethodToString fix --- IDEHelper/Compiler/BfExprEvaluator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 7ab34ee4..1b866f6b 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -11715,7 +11715,7 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr) } else { - mModule->Fail(StrFormat("Method '%s' does not match %s '%s'", mModule->MethodToString(bindMethodInstance, (BfMethodNameFlags)(BfMethodNameFlag_IncludeReturnType | BfMethodNameFlag_IncludeMut)).c_str(), bindTypeName, + mModule->Fail(StrFormat("Method '%s' does not match %s '%s'", mModule->MethodToString(bindMethodInstance, (BfMethodNameFlags)(BfMethodNameFlag_ResolveGenericParamNames | BfMethodNameFlag_IncludeReturnType | BfMethodNameFlag_IncludeMut)).c_str(), bindTypeName, mModule->TypeToString(delegateTypeInstance).c_str()), delegateBindExpr->mTarget); } mResult = BfTypedValue(); From 8bc5d097879504d2cab7cadbea05ad2ef6883592 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Wed, 15 Dec 2021 17:06:43 -0500 Subject: [PATCH 043/139] Error text fix --- IDE/Tests/CompileFail001/src/Generics.bf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IDE/Tests/CompileFail001/src/Generics.bf b/IDE/Tests/CompileFail001/src/Generics.bf index 8a27fbf4..6f851c63 100644 --- a/IDE/Tests/CompileFail001/src/Generics.bf +++ b/IDE/Tests/CompileFail001/src/Generics.bf @@ -52,7 +52,7 @@ namespace IDETest void MethodB() { - function void() f = => MethodA; //FAIL Method 'IDETest.Generics.ClassA.MethodA(int a)' does not match function 'function void()' + function void() f = => MethodA; //FAIL Method 'void IDETest.Generics.ClassA.MethodA(int a)' does not match function 'function void()' } } From 2932fceae4b905bf70d2b9a795f769fbf66e8cba Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Thu, 16 Dec 2021 07:28:03 -0500 Subject: [PATCH 044/139] Allow boxed types to utilize comptime methods --- IDEHelper/Compiler/BfContext.cpp | 26 +++++++--- IDEHelper/Compiler/BfModule.cpp | 8 +-- IDEHelper/Compiler/BfModuleTypeUtils.cpp | 29 +++++++---- IDEHelper/Compiler/BfResolvedTypeUtils.cpp | 7 +++ IDEHelper/Compiler/BfResolvedTypeUtils.h | 1 + IDEHelper/Compiler/BfSystem.cpp | 13 +++-- IDEHelper/Tests/src/Comptime.bf | 59 ++++++++++++++++++++++ 7 files changed, 114 insertions(+), 29 deletions(-) diff --git a/IDEHelper/Compiler/BfContext.cpp b/IDEHelper/Compiler/BfContext.cpp index 2de7a71a..f338c2f1 100644 --- a/IDEHelper/Compiler/BfContext.cpp +++ b/IDEHelper/Compiler/BfContext.cpp @@ -892,6 +892,9 @@ void BfContext::RebuildType(BfType* type, bool deleteOnDemandTypes, bool rebuild return; } + if ((typeInst->IsBoxed()) && (typeInst->mTypeDef->mEmitParent != NULL)) + typeInst->mTypeDef = typeInst->mTypeDef->mEmitParent; + if (mSystem->mWorkspaceConfigChanged) { typeInst->mTypeOptionsIdx = -2; @@ -1060,8 +1063,12 @@ void BfContext::RebuildType(BfType* type, bool deleteOnDemandTypes, bool rebuild if (typeInst->mTypeDef->mEmitParent != NULL) { auto emitTypeDef = typeInst->mTypeDef; - typeInst->mTypeDef = emitTypeDef->mEmitParent; - delete emitTypeDef; + typeInst->mTypeDef = emitTypeDef->mEmitParent; + BfLogSysM("Type %p queueing delete of typeDef %p, resetting typeDef to %p\n", typeInst, emitTypeDef, typeInst->mTypeDef); + emitTypeDef->mDefState = BfTypeDef::DefState_Deleted; + AutoCrit autoCrit(mSystem->mDataLock); + BF_ASSERT(!mSystem->mTypeDefDeleteQueue.Contains(emitTypeDef)); + mSystem->mTypeDefDeleteQueue.push_back(emitTypeDef); } //typeInst->mTypeDef->ClearEmitted(); @@ -1912,10 +1919,17 @@ void BfContext::UpdateRevisedTypes() if (typeDef->mEmitParent != NULL) { - auto emitTypeDef = typeDef; - typeDef = typeDef->mEmitParent; - if (typeDef->mNextRevision != NULL) - emitTypeDef->mDefState = BfTypeDef::DefState_EmittedDirty; + if (typeDef->mDefState == BfTypeDef::DefState_Deleted) + { + typeInst->mTypeDef = typeDef->mEmitParent; + } + else + { + auto emitTypeDef = typeDef; + typeDef = typeDef->mEmitParent; + if (typeDef->mNextRevision != NULL) + emitTypeDef->mDefState = BfTypeDef::DefState_EmittedDirty; + } } if (typeDef->mProject->mDisabled) diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 17fb80af..da894da9 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -15286,7 +15286,7 @@ void BfModule::AssertErrorState() { if (mCurTypeInstance->mTypeFailed) return; - if ((mCurTypeInstance->mTypeDef->mSource != NULL) && (mCurTypeInstance->mTypeDef->mSource->mParsingFailed)) + if ((mCurTypeInstance->mTypeDef->GetDefinition()->mSource != NULL) && (mCurTypeInstance->mTypeDef->GetDefinition()->mSource->mParsingFailed)) return; } if (mCurMethodInstance != NULL) @@ -19762,12 +19762,8 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup) mBfIRBuilder->CreateRetVoid(); } else - { - BF_ASSERT(!innerMethodInstance.mMethodInstance->mMethodDef->mDeclaringType->IsEmitted()); + { auto innerMethodDef = innerMethodInstance.mMethodInstance->mMethodDef; - if (innerType->mTypeDef->IsEmitted()) - innerMethodDef = innerType->mTypeDef->mEmitParent->mMethods[innerMethodDef->mIdx]; - BF_ASSERT(innerMethodDef == methodDef); SizedArray innerParams; diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 79ed59ae..d42ece83 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -2747,7 +2747,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy resolvedTypeRef->mSize = typeInstance->mAlign = mSystem->mPtrSize; } - BF_ASSERT((typeInstance->mMethodInstanceGroups.size() == 0) || (typeInstance->mMethodInstanceGroups.size() == typeDef->mMethods.size()) || (typeInstance->mCeTypeInfo != NULL)); + BF_ASSERT((typeInstance->mMethodInstanceGroups.size() == 0) || (typeInstance->mMethodInstanceGroups.size() == typeDef->mMethods.size()) || (typeInstance->mCeTypeInfo != NULL) || (typeInstance->IsBoxed())); typeInstance->mMethodInstanceGroups.Resize(typeDef->mMethods.size()); for (int i = 0; i < (int)typeInstance->mMethodInstanceGroups.size(); i++) { @@ -3702,6 +3702,15 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy if (innerType->IsIncomplete()) PopulateType(innerType, BfPopulateType_Data); + auto innerTypeInst = innerType->ToTypeInstance(); + if ((innerTypeInst != NULL) && (typeInstance->mTypeDef != innerTypeInst->mTypeDef)) + { + // Rebuild with proper typedef (generally from inner type comptime emission) + typeInstance->mTypeDef = innerTypeInst->mTypeDef; + DoPopulateType(resolvedTypeRef, populateType); + return; + } + auto baseType = typeInstance->mBaseType; dataPos = baseType->mInstSize; int alignSize = BF_MAX(innerType->mAlign, baseType->mInstAlign); @@ -5666,15 +5675,15 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance) } else { - auto matchedMethodDef = matchedMethod->mMethodDef; - if (matchedMethodDef->mDeclaringType->IsEmitted()) - { - Fail("Boxed interface binding error to emitted method", mCurTypeInstance->mTypeDef->GetRefNode()); - continue; - } - - if (underlyingTypeInstance->mTypeDef->IsEmitted()) - matchedMethodDef = underlyingTypeInstance->mTypeDef->mEmitParent->mMethods[matchedMethodDef->mIdx]; + auto matchedMethodDef = matchedMethod->mMethodDef; +// if (matchedMethodDef->mDeclaringType->IsEmitted()) +// { +// Fail("Boxed interface binding error to emitted method", mCurTypeInstance->mTypeDef->GetRefNode()); +// continue; +// } +// +// if (underlyingTypeInstance->mTypeDef->IsEmitted()) +// matchedMethodDef = underlyingTypeInstance->mTypeDef->mEmitParent->mMethods[matchedMethodDef->mIdx]; if (!matchedMethod->mIsForeignMethodDef) { diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp index c99a4e77..93939bec 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp @@ -1554,6 +1554,7 @@ BfTypeInstance::~BfTypeInstance() if ((mTypeDef != NULL) && (mTypeDef->mEmitParent != NULL)) { mMethodInstanceGroups.Clear(); + BfLogSys(mModule->mSystem, "Type %p dtor deleting typeDef %p\n", this, mTypeDef); delete mTypeDef; } } @@ -2627,6 +2628,12 @@ void BfTupleType::Finish() ////////////////////////////////////////////////////////////////////////// +BfBoxedType::~BfBoxedType() +{ + if (mTypeDef->mEmitParent != NULL) + mTypeDef = mTypeDef->mEmitParent; +} + BfType* BfBoxedType::GetModifiedElementType() { if ((mBoxedFlags & BoxedFlags_StructPtr) != 0) diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index 7563609d..858fc5d0 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -2110,6 +2110,7 @@ public: mBoxedBaseType = NULL; mBoxedFlags = BoxedFlags_None; } + ~BfBoxedType(); virtual bool IsBoxed() override { return true; } diff --git a/IDEHelper/Compiler/BfSystem.cpp b/IDEHelper/Compiler/BfSystem.cpp index 0f0419bd..78f16b8f 100644 --- a/IDEHelper/Compiler/BfSystem.cpp +++ b/IDEHelper/Compiler/BfSystem.cpp @@ -793,11 +793,6 @@ BfTypeDef::~BfTypeDef() { BfLogSysM("BfTypeDef::~BfTypeDef %p\n", this); - if ((mHash == -1330357811) && (IsEmitted())) - { - NOP; - } - delete mNextRevision; FreeMembers(); @@ -3728,10 +3723,14 @@ void BfSystem::RemoveOldData() { AutoCrit autoCrit(mDataLock); - for (auto typeDef : mTypeDefDeleteQueue) + for (int i = 0; i < (int)mTypeDefDeleteQueue.size(); i++) + { + auto typeDef = mTypeDefDeleteQueue[i]; + mTypeDefDeleteQueue[i] = NULL; + BfLogSys(this, "RemoveOldData deleting from mTypeDefDeleteQueue %p\n", typeDef); delete typeDef; + } mTypeDefDeleteQueue.Clear(); - if (!mProjectDeleteQueue.IsEmpty()) { diff --git a/IDEHelper/Tests/src/Comptime.bf b/IDEHelper/Tests/src/Comptime.bf index 385b6fa7..97be881c 100644 --- a/IDEHelper/Tests/src/Comptime.bf +++ b/IDEHelper/Tests/src/Comptime.bf @@ -174,7 +174,60 @@ namespace Tests public float mY; public float mZ; } + + class SerializationContext + { + public String mStr = new String() ~ delete _; + public void Serialize(String name, T val) where T : struct + { + mStr.AppendF($"{name} {val}\n"); + } + } + 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 + where T : struct + { + uint8* data; + protected override void GCMarkMembers() + { + T* ptr = (T*)data; + GC.Mark!((*ptr)); + } + } [Test] public static void TestBasics() { @@ -209,6 +262,12 @@ namespace Tests 4 mY 8 mZ """); + + Foo bar = .(10, 2); + ISerializable iSer = bar; + SerializationContext serCtx = scope .(); + iSer.Serialize(serCtx); + Test.Assert(serCtx.mStr == "x 10\ny 2\n"); } } } From 224a17e6694992c19e9d535b7e9aaa13601f256b Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Thu, 16 Dec 2021 07:49:39 -0500 Subject: [PATCH 045/139] Fixed ability to view huge (>2GB) spans --- IDE/src/ui/WatchPanel.bf | 2 +- IDEHelper/WinDebugger.cpp | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/IDE/src/ui/WatchPanel.bf b/IDE/src/ui/WatchPanel.bf index 497beab4..06da55be 100644 --- a/IDE/src/ui/WatchPanel.bf +++ b/IDE/src/ui/WatchPanel.bf @@ -1295,7 +1295,7 @@ namespace IDE.ui addrsCount = mWatchSeriesInfo.mAddrs.Length / entryAddrSize; int totalCount = mWatchSeriesInfo.mCount; - if (totalCount == -1) + if ((totalCount == -1) && (mWatchSeriesInfo.mContinuationData != null)) { //int wantNewCount = Math.Min(idx + 32, mWatchSeriesInfo.mCount) - addrsCount; bool continuationDone = false; diff --git a/IDEHelper/WinDebugger.cpp b/IDEHelper/WinDebugger.cpp index c2d98fa6..247f57e9 100644 --- a/IDEHelper/WinDebugger.cpp +++ b/IDEHelper/WinDebugger.cpp @@ -8415,7 +8415,7 @@ void WinDebugger::HandleCustomExpandedItems(String& retVal, DbgCompileUnit* dbgC evalStr += ", refid=\"" + referenceId + ".[]\""; if (isReadOnly) evalStr += ", ne"; - retVal += "\n:repeat" + StrFormat("\t%d\t%d\t%d", 0, (int)sizeValue.GetInt64() / dimSize1, 50000) + + retVal += "\n:repeat" + StrFormat("\t%d\t%lld\t%d", 0, sizeValue.GetInt64() / dimSize1, 50000) + "\t[{0}]\t" + evalStr; } else if (lowerDimSizes.size() == 2) @@ -8431,7 +8431,7 @@ void WinDebugger::HandleCustomExpandedItems(String& retVal, DbgCompileUnit* dbgC evalStr += ", refid=\"" + referenceId + ".[]\""; if (isReadOnly) evalStr += ", ne"; - retVal += "\n:repeat" + StrFormat("\t%d\t%d\t%d", 0, (int)sizeValue.GetInt64() / dimSize1 / dimSize2, 50000) + + retVal += "\n:repeat" + StrFormat("\t%d\t%lld\t%d", 0, sizeValue.GetInt64() / dimSize1 / dimSize2, 50000) + "\t[{0}]\t" + evalStr; } } @@ -8449,7 +8449,7 @@ void WinDebugger::HandleCustomExpandedItems(String& retVal, DbgCompileUnit* dbgC evalStr += ", refid=\"" + referenceId + ".[]\""; if (isReadOnly) evalStr += ", ne"; - retVal += "\n:repeat" + StrFormat("\t%d\t%d\t%d", 0, (int)sizeValue.GetInt64() / dimSize1 / dimSize2 / dimSize3, 50000) + + retVal += "\n:repeat" + StrFormat("\t%d\t%lld\t%d", 0, sizeValue.GetInt64() / dimSize1 / dimSize2 / dimSize3, 50000) + "\t[{0}]\t" + evalStr; } } @@ -8459,7 +8459,7 @@ void WinDebugger::HandleCustomExpandedItems(String& retVal, DbgCompileUnit* dbgC evalStr += ", refid=\"" + referenceId + ".[]\""; if (isReadOnly) evalStr += ", ne"; - retVal += "\n:repeat" + StrFormat("\t%d\t%d\t%d", 0, (int)sizeValue.GetInt64(), 50000) + + retVal += "\n:repeat" + StrFormat("\t%d\t%lld\t%d", 0, sizeValue.GetInt64(), 50000) + "\t[{0}]\t" + evalStr; } } @@ -8476,7 +8476,7 @@ void WinDebugger::HandleCustomExpandedItems(String& retVal, DbgCompileUnit* dbgC evalStr += ", refid=\"" + referenceId + ".[]\""; if (isReadOnly) evalStr += ", ne"; - retVal += "\n:repeat" + StrFormat("\t%d\t%d\t%d", 0, (int)sizeValue.GetInt64(), 50000) + + retVal += "\n:repeat" + StrFormat("\t%d\t%lld\t%d", 0, sizeValue.GetInt64(), 50000) + "\t[{0}]\t" + evalStr; } } From 7b65f8887e080b9f807e37a69f799ac6de8909f6 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Thu, 16 Dec 2021 08:00:20 -0500 Subject: [PATCH 046/139] Fixed autocomplete stack overflow --- IDE/src/Compiler/BfCompiler.bf | 4 ++-- IDEHelper/Compiler/BfSystem.cpp | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/IDE/src/Compiler/BfCompiler.bf b/IDE/src/Compiler/BfCompiler.bf index d391831a..efc60b19 100644 --- a/IDE/src/Compiler/BfCompiler.bf +++ b/IDE/src/Compiler/BfCompiler.bf @@ -243,13 +243,13 @@ namespace IDE.Compiler public void GetAutocompleteInfo(String outAutocompleteInfo) { char8* result = BfCompiler_GetAutocompleteInfo(mNativeBfCompiler); - scope String(result).MoveTo(outAutocompleteInfo); + outAutocompleteInfo.Append(StringView(result)); } public void GetSymbolReferences(BfPassInstance passInstance, BfResolvePassData resolvePassData, String outSymbolReferences) { char8* result = BfCompiler_GetSymbolReferences(mNativeBfCompiler, passInstance.mNativeBfPassInstance, resolvePassData.mNativeResolvePassData); - scope String(result).MoveTo(outSymbolReferences); + outSymbolReferences.Append(StringView(result)); } /*public void UpdateRenameSymbols(BfPassInstance passInstance, BfResolvePassData resolvePassData) diff --git a/IDEHelper/Compiler/BfSystem.cpp b/IDEHelper/Compiler/BfSystem.cpp index 78f16b8f..de407542 100644 --- a/IDEHelper/Compiler/BfSystem.cpp +++ b/IDEHelper/Compiler/BfSystem.cpp @@ -3763,6 +3763,7 @@ void BfSystem::RemoveOldData() void BfSystem::VerifyTypeDef(BfTypeDef* typeDef) { +#if defined _DEBUG && false auto _FindTypeDef = [&](BfTypeReference* typeRef) { if (auto directStrTypeRef = BfNodeDynCast(typeRef)) @@ -3796,6 +3797,7 @@ void BfSystem::VerifyTypeDef(BfTypeDef* typeDef) _FindTypeDef(paramDef->mTypeRef); } } +#endif } BfTypeOptions* BfSystem::GetTypeOptions(int optionsIdx) From 9f4a75dba354dc7bf020c0e76b29616dbb93904f Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Thu, 16 Dec 2021 08:26:33 -0500 Subject: [PATCH 047/139] Fixed boxed type dtor --- IDEHelper/Compiler/BfResolvedTypeUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp index 93939bec..dcee546b 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp @@ -2630,7 +2630,7 @@ void BfTupleType::Finish() BfBoxedType::~BfBoxedType() { - if (mTypeDef->mEmitParent != NULL) + if ((mTypeDef != NULL) && (mTypeDef->mEmitParent != NULL)) mTypeDef = mTypeDef->mEmitParent; } From 612368b0f7750f54c6074860eac11dfbb20fa37d Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Thu, 16 Dec 2021 09:38:19 -0500 Subject: [PATCH 048/139] Comptime EmitAddInterface --- BeefLibs/corlib/src/Compiler.bf | 7 +++ IDEHelper/Compiler/BfModuleTypeUtils.cpp | 63 ++++++++++++++++++------ IDEHelper/Compiler/BfResolvedTypeUtils.h | 1 + IDEHelper/Compiler/CeMachine.cpp | 15 ++++++ IDEHelper/Compiler/CeMachine.h | 2 + IDEHelper/Tests/src/Comptime.bf | 3 +- 6 files changed, 74 insertions(+), 17 deletions(-) diff --git a/BeefLibs/corlib/src/Compiler.bf b/BeefLibs/corlib/src/Compiler.bf index cb706d01..3030c444 100644 --- a/BeefLibs/corlib/src/Compiler.bf +++ b/BeefLibs/corlib/src/Compiler.bf @@ -257,6 +257,7 @@ namespace System 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_EmitAddInterface(int32 typeId, int32 ifaceTypeId); 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); @@ -275,6 +276,12 @@ namespace System Comptime_EmitTypeBody((.)owner.TypeId, text); } + [Comptime(OnlyFromComptime=true)] + public static void EmitAddInterface(Type owner, Type iface) + { + Comptime_EmitAddInterface((.)owner.TypeId, (.)iface.TypeId); + } + [Comptime(OnlyFromComptime=true)] public static void EmitMethodEntry(ComptimeMethodInfo methodHandle, StringView text) { diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index d42ece83..6ee0e55f 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -2076,6 +2076,9 @@ void BfModule::FinishCEParseContext(BfAstNode* refNode, BfTypeInstance* typeInst void BfModule::UpdateCEEmit(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance, const StringImpl& ctxString, BfAstNode* refNode) { + for (int ifaceTypeId : ceEmitContext->mInterfaces) + typeInstance->mCeTypeInfo->mPendingInterfaces.Add(ifaceTypeId); + if (ceEmitContext->mEmitData.IsEmpty()) return; @@ -3313,6 +3316,27 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy wantPopulateInterfaces = true; } + if ((typeInstance->mCeTypeInfo != NULL) && (!typeInstance->mCeTypeInfo->mPendingInterfaces.IsEmpty())) + { + for (auto ifaceTypeId : typeInstance->mCeTypeInfo->mPendingInterfaces) + { + auto ifaceType = mContext->mTypes[ifaceTypeId]; + if ((ifaceType == NULL) || (!ifaceType->IsInterface())) + continue; + auto ifaceInst = ifaceType->ToTypeInstance(); + + if (ifaceSet.Add(ifaceInst)) + { + // Not base type + BfInterfaceDecl ifaceDecl; + ifaceDecl.mIFaceTypeInst = ifaceInst; + ifaceDecl.mTypeRef = NULL; + ifaceDecl.mDeclaringType = typeDef->GetDefinition(); + interfaces.Add(ifaceDecl); + } + } + } + if (_CheckTypeDone()) return; @@ -3703,12 +3727,22 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy PopulateType(innerType, BfPopulateType_Data); auto innerTypeInst = innerType->ToTypeInstance(); - if ((innerTypeInst != NULL) && (typeInstance->mTypeDef != innerTypeInst->mTypeDef)) + if (innerTypeInst != NULL) { - // Rebuild with proper typedef (generally from inner type comptime emission) - typeInstance->mTypeDef = innerTypeInst->mTypeDef; - DoPopulateType(resolvedTypeRef, populateType); - return; + if (typeInstance->mTypeDef != innerTypeInst->mTypeDef) + { + // Rebuild with proper typedef (generally from inner type comptime emission) + typeInstance->mTypeDef = innerTypeInst->mTypeDef; + DoPopulateType(resolvedTypeRef, populateType); + return; + } + + while (typeInstance->mInterfaces.mSize < innerTypeInst->mInterfaces.mSize) + { + auto ifaceEntry = innerTypeInst->mInterfaces[typeInstance->mInterfaces.mSize]; + typeInstance->mInterfaces.Add(ifaceEntry); + AddDependency(ifaceEntry.mInterfaceType, typeInstance, BfDependencyMap::DependencyFlag_ImplementsInterface); + } } auto baseType = typeInstance->mBaseType; @@ -4014,9 +4048,12 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy } if ((typeInstance->mDefineState < BfTypeDefineState_CEPostTypeInit) && (tryCE)) - { + { BF_ASSERT(!typeInstance->mTypeDef->IsEmitted()); + if (typeInstance->mCeTypeInfo != NULL) + typeInstance->mCeTypeInfo->mPendingInterfaces.Clear(); + typeInstance->mDefineState = BfTypeDefineState_CETypeInit; bool hadNewMembers = false; DoCEEmit(typeInstance, hadNewMembers); @@ -4071,6 +4108,9 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy } } + if ((typeInstance->mCeTypeInfo != NULL) && (!typeInstance->mCeTypeInfo->mPendingInterfaces.IsEmpty())) + hadNewMembers = true; + if ((typeInstance->mTypeDef->IsEmitted()) && (typeInstance->mCeTypeInfo == NULL)) { BF_ASSERT(mCompiler->mCanceling); @@ -5676,15 +5716,6 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance) else { auto matchedMethodDef = matchedMethod->mMethodDef; -// if (matchedMethodDef->mDeclaringType->IsEmitted()) -// { -// Fail("Boxed interface binding error to emitted method", mCurTypeInstance->mTypeDef->GetRefNode()); -// continue; -// } -// -// if (underlyingTypeInstance->mTypeDef->IsEmitted()) -// matchedMethodDef = underlyingTypeInstance->mTypeDef->mEmitParent->mMethods[matchedMethodDef->mIdx]; - if (!matchedMethod->mIsForeignMethodDef) { BfMethodInstanceGroup* boxedMethodInstanceGroup = &typeInstance->mMethodInstanceGroups[matchedMethod->mMethodDef->mIdx]; @@ -5693,7 +5724,7 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance) boxedMethodInstanceGroup->mOnDemandKind = BfMethodOnDemandKind_Decl_AwaitingDecl; VerifyOnDemandMethods(); } - } + } auto methodFlags = matchedMethod->mIsForeignMethodDef ? BfGetMethodInstanceFlag_ForeignMethodDef : BfGetMethodInstanceFlag_None; methodFlags = (BfGetMethodInstanceFlags)(methodFlags | BfGetMethodInstanceFlag_MethodInstanceOnly); diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index 858fc5d0..9b9a1321 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -1828,6 +1828,7 @@ class BfCeTypeInfo public: Dictionary mOnCompileMap; Dictionary mTypeIFaceMap; + Array mPendingInterfaces; Val128 mHash; bool mFailed; BfCeTypeInfo* mNext; diff --git a/IDEHelper/Compiler/CeMachine.cpp b/IDEHelper/Compiler/CeMachine.cpp index 579630e3..b8054687 100644 --- a/IDEHelper/Compiler/CeMachine.cpp +++ b/IDEHelper/Compiler/CeMachine.cpp @@ -4740,6 +4740,17 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* return false; } } + else if (checkFunction->mFunctionKind == CeFunctionKind_EmitAddInterface) + { + int32 typeId = *(int32*)((uint8*)stackPtr); + int32 ifaceTypeId = *(int32*)((uint8*)stackPtr + sizeof(int32)); + if ((mCurEmitContext == NULL) || (mCurEmitContext->mType->mTypeId != typeId)) + { + _Fail("Code cannot be emitted for this type in this context"); + return false; + } + mCurEmitContext->mInterfaces.Add(ifaceTypeId); + } else if (checkFunction->mFunctionKind == CeFunctionKind_EmitMethodEntry) { int64 methodHandle = *(int64*)((uint8*)stackPtr); @@ -6833,6 +6844,10 @@ void CeMachine::CheckFunctionKind(CeFunction* ceFunction) { ceFunction->mFunctionKind = CeFunctionKind_EmitTypeBody; } + if (methodDef->mName == "Comptime_EmitAddInterface") + { + ceFunction->mFunctionKind = CeFunctionKind_EmitAddInterface; + } else if (methodDef->mName == "Comptime_EmitMethodEntry") { ceFunction->mFunctionKind = CeFunctionKind_EmitMethodEntry; diff --git a/IDEHelper/Compiler/CeMachine.h b/IDEHelper/Compiler/CeMachine.h index 071b1e4a..6c211e25 100644 --- a/IDEHelper/Compiler/CeMachine.h +++ b/IDEHelper/Compiler/CeMachine.h @@ -289,6 +289,7 @@ enum CeFunctionKind CeFunctionKind_Method_GetParamInfo, CeFunctionKind_EmitTypeBody, + CeFunctionKind_EmitAddInterface, CeFunctionKind_EmitMethodEntry, CeFunctionKind_EmitMethodExit, CeFunctionKind_EmitMixin, @@ -687,6 +688,7 @@ class CeEmitContext public: BfType* mType; BfMethodInstance* mMethodInstance; + Array mInterfaces; String mEmitData; String mExitEmitData; bool mFailed; diff --git a/IDEHelper/Tests/src/Comptime.bf b/IDEHelper/Tests/src/Comptime.bf index 97be881c..453e39c7 100644 --- a/IDEHelper/Tests/src/Comptime.bf +++ b/IDEHelper/Tests/src/Comptime.bf @@ -210,11 +210,12 @@ namespace Tests } Compiler.EmitTypeBody(type, scope $"{SERIALIZE_NAME}{{{serializeBuffer}\n}}\n"); + Compiler.EmitAddInterface(type, typeof(ISerializable)); } } [Serializable] - struct Foo : this(float x, float y), ISerializable + struct Foo : this(float x, float y) { } From a70aecf69204a4041c8a32c53e502cd99c2b8263 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Thu, 16 Dec 2021 09:42:43 -0500 Subject: [PATCH 049/139] BoxedType dtor change --- IDEHelper/Compiler/BfResolvedTypeUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp index dcee546b..26ba94bc 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp @@ -2631,7 +2631,7 @@ void BfTupleType::Finish() BfBoxedType::~BfBoxedType() { if ((mTypeDef != NULL) && (mTypeDef->mEmitParent != NULL)) - mTypeDef = mTypeDef->mEmitParent; + mTypeDef = NULL; } BfType* BfBoxedType::GetModifiedElementType() From 9bb34ce029d43e1ecc97ea752a0827a679f48682 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Thu, 16 Dec 2021 10:08:38 -0500 Subject: [PATCH 050/139] Const eval fix for comptime method args --- IDEHelper/Compiler/BfExprEvaluator.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 1b866f6b..c0f6a333 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -5090,7 +5090,9 @@ void BfExprEvaluator::ResolveArgValues(BfResolvedArgs& resolvedArgs, BfResolveAr BfExprEvaluator exprEvaluator(mModule); exprEvaluator.mResolveGenericParam = (flags & BfResolveArgsFlag_AllowUnresolvedTypes) == 0; - exprEvaluator.mBfEvalExprFlags = (BfEvalExprFlags)(exprEvaluator.mBfEvalExprFlags | BfEvalExprFlags_AllowRefExpr | BfEvalExprFlags_AllowOutExpr); + exprEvaluator.mBfEvalExprFlags = (BfEvalExprFlags)(exprEvaluator.mBfEvalExprFlags | BfEvalExprFlags_AllowRefExpr | BfEvalExprFlags_AllowOutExpr | + (mBfEvalExprFlags & (BfEvalExprFlags_Comptime))); + bool handled = false; bool evaluated = false; From 0ee161c314a7786fd5ae4566d6391d830cd86e82 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Thu, 16 Dec 2021 10:20:09 -0500 Subject: [PATCH 051/139] Better error for comptime initializer expressions --- IDEHelper/Compiler/BfExprEvaluator.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index c0f6a333..a7750009 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -10148,6 +10148,12 @@ void BfExprEvaluator::Visit(BfInitializerExpression* initExpr) for (auto elementExpr : initExpr->mValues) { + if ((mBfEvalExprFlags & BfEvalExprFlags_Comptime) != 0) + { + mModule->Fail("Comptime cannot evaluate initializer expressions", elementExpr); + break; + } + bool wasValidInitKind = false; if (auto assignExpr = BfNodeDynCast(elementExpr)) From def7990dbe0327129d77bab9cdbef6684ab932de Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Thu, 16 Dec 2021 11:00:56 -0500 Subject: [PATCH 052/139] More support for bitcasts with consts --- IDEHelper/Compiler/BfIRBuilder.cpp | 40 +++++++++++++----------- IDEHelper/Compiler/BfIRBuilder.h | 1 + IDEHelper/Compiler/BfModule.cpp | 28 ++++++++++++++--- IDEHelper/Compiler/BfModuleTypeUtils.cpp | 2 +- 4 files changed, 47 insertions(+), 24 deletions(-) diff --git a/IDEHelper/Compiler/BfIRBuilder.cpp b/IDEHelper/Compiler/BfIRBuilder.cpp index b524fdd9..8e1ace33 100644 --- a/IDEHelper/Compiler/BfIRBuilder.cpp +++ b/IDEHelper/Compiler/BfIRBuilder.cpp @@ -857,6 +857,26 @@ BfIRValue BfIRConstHolder::CreateConstArrayZero(int count) return irValue; } +BfIRValue BfIRConstHolder::CreateConstBitCast(BfIRValue val, BfIRType type) +{ + auto constVal = GetConstant(val); + + auto bitCast = mTempAlloc.Alloc(); + if ((constVal == NULL) || (constVal->IsNull())) + bitCast->mConstType = BfConstType_BitCastNull; + else + bitCast->mConstType = BfConstType_BitCast; + bitCast->mTarget = val.mId; + bitCast->mToType = type; + + BfIRValue castedVal(BfIRValueFlags_Const, mTempAlloc.GetChunkedId(bitCast)); +#ifdef CHECK_CONSTHOLDER + castedVal.mHolder = this; +#endif + BF_ASSERT((void*)GetConstant(castedVal) == (void*)bitCast); + return castedVal; +} + BfIRValue BfIRConstHolder::CreateTypeOf(BfType* type) { BfTypeOf_Const* typeOf = mTempAlloc.Alloc(); @@ -4414,25 +4434,7 @@ BfIRValue BfIRBuilder::CreateNot(BfIRValue val) BfIRValue BfIRBuilder::CreateBitCast(BfIRValue val, BfIRType type) { if (val.IsConst()) - { - auto constVal = GetConstant(val); - - auto bitCast = mTempAlloc.Alloc(); - if (constVal->IsNull()) - bitCast->mConstType = BfConstType_BitCastNull; - else - bitCast->mConstType = BfConstType_BitCast; - bitCast->mTarget = val.mId; - bitCast->mToType = type; - - BfIRValue castedVal(BfIRValueFlags_Const, mTempAlloc.GetChunkedId(bitCast)); -#ifdef CHECK_CONSTHOLDER - castedVal.mHolder = this; -#endif - BF_ASSERT((void*)GetConstant(castedVal) == (void*)bitCast); - return castedVal; - } - + return CreateConstBitCast(val, type); auto retVal = WriteCmd(BfIRCmd_BitCast, val, type); NEW_CMD_INSERTED_IRVALUE; return retVal; diff --git a/IDEHelper/Compiler/BfIRBuilder.h b/IDEHelper/Compiler/BfIRBuilder.h index 3d045deb..64c0f55d 100644 --- a/IDEHelper/Compiler/BfIRBuilder.h +++ b/IDEHelper/Compiler/BfIRBuilder.h @@ -934,6 +934,7 @@ public: BfIRValue CreateConstAggCE(BfIRType type, addr_ce ptr); BfIRValue CreateConstArrayZero(BfIRType type, int count); BfIRValue CreateConstArrayZero(int count); + BfIRValue CreateConstBitCast(BfIRValue val, BfIRType type); BfIRValue CreateTypeOf(BfType* type); BfIRValue CreateTypeOf(BfType* type, BfIRValue typeData); BfIRValue GetUndefConstValue(BfIRType type); diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index da894da9..ba13dae6 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -10873,8 +10873,15 @@ void BfModule::CurrentAddToConstHolder(BfIRValue& irVal) auto origConst = irVal; if ((constant->mConstType == BfConstType_BitCast) || (constant->mConstType == BfConstType_BitCastNull)) { - auto bitcast = (BfConstantBitCast*)constant; - constant = mBfIRBuilder->GetConstantById(bitcast->mTarget); + auto bitcast = (BfConstantBitCast*)constant; + BfIRValue newVal; + if (bitcast->mTarget) + { + newVal = BfIRValue(BfIRValueFlags_Const, bitcast->mTarget); + CurrentAddToConstHolder(newVal); + } + irVal = mCurTypeInstance->GetOrCreateConstHolder()->CreateConstBitCast(newVal, bitcast->mToType); + return; } irVal = mCurTypeInstance->CreateConst(constant, mBfIRBuilder); @@ -10999,7 +11006,7 @@ BfIRValue BfModule::ConstantToCurrent(BfConstant* constant, BfIRConstHolder* con wantType = mContext->mTypes[constant->mIRType.mId]; if (wantType == NULL) - return constHolder->CreateConstNull(); + return mBfIRBuilder->CreateConstNull(); return GetDefaultValue(wantType); } @@ -11047,8 +11054,21 @@ BfIRValue BfModule::ConstantToCurrent(BfConstant* constant, BfIRConstHolder* con return mBfIRBuilder->CreateIntToPtr(ConstantToCurrent(fromTarget, constHolder, NULL), toIRType); } + if ((constant->mConstType == BfConstType_BitCast) || (constant->mConstType == BfConstType_BitCastNull)) + { + auto bitcast = (BfConstantBitCast*)constant; + auto fromTarget = constHolder->GetConstantById(bitcast->mTarget); + BfIRType toIRType = bitcast->mToType; + if (toIRType.mKind == BfIRTypeData::TypeKind_TypeId) + { + auto toType = mContext->mTypes[toIRType.mId]; + toIRType = mBfIRBuilder->MapType(toType); + } + return mBfIRBuilder->CreateBitCast(ConstantToCurrent(fromTarget, constHolder, NULL), toIRType); + } + if (constant->mConstType == BfConstType_Agg) - { + { auto constArray = (BfConstantAgg*)constant; if ((wantType == NULL) && (constArray->mType.mKind == BfIRTypeData::TypeKind_TypeId)) diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 6ee0e55f..c134dc85 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -11811,7 +11811,7 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp if (allowCast) { - if (ignoreWrites) + if ((ignoreWrites) && (!typedVal.mValue.IsConst())) return mBfIRBuilder->GetFakeVal(); return mBfIRBuilder->CreateBitCast(typedVal.mValue, mBfIRBuilder->MapType(toType)); } From d3e33365f03f24f6c77579615e288a9393df4345 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Thu, 16 Dec 2021 11:08:29 -0500 Subject: [PATCH 053/139] Made GCMarkMembers call unbound --- BeefLibs/corlib/src/GC.bf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BeefLibs/corlib/src/GC.bf b/BeefLibs/corlib/src/GC.bf index 231642a3..98055aa4 100644 --- a/BeefLibs/corlib/src/GC.bf +++ b/BeefLibs/corlib/src/GC.bf @@ -163,7 +163,7 @@ namespace System public static mixin Mark(T val) where T : struct { #if BF_ENABLE_REALTIME_LEAK_CHECK - val.[Friend]GCMarkMembers(); + val.[Friend, Unbound]GCMarkMembers(); #endif } From 7115cb8e826d10872c386cf5d47887e0b6cccd20 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Thu, 16 Dec 2021 11:18:57 -0500 Subject: [PATCH 054/139] Fixed bitcast null issue --- IDEHelper/Compiler/BfIRBuilder.cpp | 1 + IDEHelper/Compiler/BfModule.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/IDEHelper/Compiler/BfIRBuilder.cpp b/IDEHelper/Compiler/BfIRBuilder.cpp index 8e1ace33..95307c23 100644 --- a/IDEHelper/Compiler/BfIRBuilder.cpp +++ b/IDEHelper/Compiler/BfIRBuilder.cpp @@ -866,6 +866,7 @@ BfIRValue BfIRConstHolder::CreateConstBitCast(BfIRValue val, BfIRType type) bitCast->mConstType = BfConstType_BitCastNull; else bitCast->mConstType = BfConstType_BitCast; + BF_ASSERT(val.mId != -1); bitCast->mTarget = val.mId; bitCast->mToType = type; diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index ba13dae6..1454d2ec 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -10880,6 +10880,8 @@ void BfModule::CurrentAddToConstHolder(BfIRValue& irVal) newVal = BfIRValue(BfIRValueFlags_Const, bitcast->mTarget); CurrentAddToConstHolder(newVal); } + else + newVal = mCurTypeInstance->GetOrCreateConstHolder()->CreateConstNull(); irVal = mCurTypeInstance->GetOrCreateConstHolder()->CreateConstBitCast(newVal, bitcast->mToType); return; } From af4a402a5342a1ea1e558473c4f299932994e227 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Thu, 16 Dec 2021 12:06:38 -0500 Subject: [PATCH 055/139] Fixed adding emitted interfaces when no emitted code is added --- IDEHelper/Compiler/BfModuleTypeUtils.cpp | 4 ++-- IDEHelper/Compiler/CeMachine.h | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index c134dc85..70fa7133 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -2201,7 +2201,7 @@ void BfModule::HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance* } } } - else if (!ceEmitContext->mEmitData.IsEmpty()) + else if (ceEmitContext->HasEmissions()) { if (typeInstance->mCeTypeInfo == NULL) typeInstance->mCeTypeInfo = new BfCeTypeInfo(); @@ -2213,7 +2213,7 @@ void BfModule::HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance->mCeTypeInfo->mNext->mTypeIFaceMap[typeId] = entry; } - if (!ceEmitContext->mEmitData.IsEmpty()) + if (ceEmitContext->HasEmissions()) { String ctxStr = "comptime ApplyToType of "; ctxStr += TypeToString(attrType); diff --git a/IDEHelper/Compiler/CeMachine.h b/IDEHelper/Compiler/CeMachine.h index 6c211e25..ca36f4b0 100644 --- a/IDEHelper/Compiler/CeMachine.h +++ b/IDEHelper/Compiler/CeMachine.h @@ -699,6 +699,11 @@ public: mMethodInstance = NULL; mFailed = false; } + + bool HasEmissions() + { + return !mEmitData.IsEmpty() || !mInterfaces.IsEmpty(); + } }; class CeContext From 5cc6f13af46b003150b6870f36b3de38dbe7dfd1 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Fri, 17 Dec 2021 07:12:27 -0500 Subject: [PATCH 056/139] Merge vista code into main FileDialog --- BeefLibs/corlib/src/IO/FileDialog.Vista.bf | 138 --------------------- BeefLibs/corlib/src/IO/FileDialog.bf | 124 ++++++++++++++++++ 2 files changed, 124 insertions(+), 138 deletions(-) delete mode 100644 BeefLibs/corlib/src/IO/FileDialog.Vista.bf diff --git a/BeefLibs/corlib/src/IO/FileDialog.Vista.bf b/BeefLibs/corlib/src/IO/FileDialog.Vista.bf deleted file mode 100644 index 2bef240c..00000000 --- a/BeefLibs/corlib/src/IO/FileDialog.Vista.bf +++ /dev/null @@ -1,138 +0,0 @@ -// This file contains portions of code released by Microsoft under the MIT license as part -// of an open-sourcing initiative in 2014 of the C# core libraries. -// The original source was submitted to https://github.com/Microsoft/referencesource - -using System.Diagnostics; -using System.Collections; - -#if BF_PLATFORM_WINDOWS -namespace System.IO -{ - extension FileDialog - { - protected abstract Result CreateVistaDialog(); - - private Result TryRunDialogVista(Windows.HWnd hWndOwner) - { - Windows.COM_IFileDialog* dialog; - if (!(CreateVistaDialog() case .Ok(out dialog))) - return .Err; - - OnBeforeVistaDialog(dialog); - dialog.VT.Show(dialog, hWndOwner); - - List files = scope .(); - ProcessVistaFiles(dialog, files); - - DeleteContainerAndItems!(mFileNames); - mFileNames = new String[files.Count]; - files.CopyTo(mFileNames); - - dialog.VT.Release(dialog); - - return .Ok(files.IsEmpty ? .Cancel : .OK); - } - - private void OnBeforeVistaDialog(Windows.COM_IFileDialog* dialog) - { - dialog.VT.SetDefaultExtension(dialog, DefaultExt.ToScopedNativeWChar!()); - - if (mFileNames != null && !mFileNames.IsEmpty) - dialog.VT.SetFileName(dialog, mFileNames[0].ToScopedNativeWChar!()); - - if (!String.IsNullOrEmpty(mInitialDir)) - { - Windows.COM_IShellItem* folderShellItem = null; - Windows.SHCreateItemFromParsingName(mInitialDir.ToScopedNativeWChar!(), null, Windows.COM_IShellItem.sIID, (void**)&folderShellItem); - if (folderShellItem != null) - { - dialog.VT.SetDefaultFolder(dialog, folderShellItem); - dialog.VT.SetFolder(dialog, folderShellItem); - folderShellItem.VT.Release(folderShellItem); - } - } - - dialog.VT.SetTitle(dialog, mTitle.ToScopedNativeWChar!()); - dialog.VT.SetOptions(dialog, GetOptions()); - SetFileTypes(dialog); - } - - private Windows.COM_IFileDialog.FOS GetOptions() - { - const Windows.COM_IFileDialog.FOS BlittableOptions = - Windows.COM_IFileDialog.FOS.OVERWRITEPROMPT - | Windows.COM_IFileDialog.FOS.NOCHANGEDIR - | Windows.COM_IFileDialog.FOS.NOVALIDATE - | Windows.COM_IFileDialog.FOS.ALLOWMULTISELECT - | Windows.COM_IFileDialog.FOS.PATHMUSTEXIST - | Windows.COM_IFileDialog.FOS.FILEMUSTEXIST - | Windows.COM_IFileDialog.FOS.CREATEPROMPT - | Windows.COM_IFileDialog.FOS.NODEREFERENCELINKS; - - const int32 UnexpectedOptions = - (int32)(Windows.OFN_SHOWHELP // If ShowHelp is true, we don't use the Vista Dialog - | Windows.OFN_ENABLEHOOK // These shouldn't be set in options (only set in the flags for the legacy dialog) - | Windows.OFN_ENABLESIZING // These shouldn't be set in options (only set in the flags for the legacy dialog) - | Windows.OFN_EXPLORER); // These shouldn't be set in options (only set in the flags for the legacy dialog) - - Debug.Assert((UnexpectedOptions & mOptions) == 0, "Unexpected FileDialog options"); - - Windows.COM_IFileDialog.FOS ret = (Windows.COM_IFileDialog.FOS)mOptions & BlittableOptions; - - // Force no mini mode for the SaveFileDialog - ret |= Windows.COM_IFileDialog.FOS.DEFAULTNOMINIMODE; - - // Make sure that the Open dialog allows the user to specify - // non-file system locations. This flag will cause the dialog to copy the resource - // to a local cache (Temporary Internet Files), and return that path instead. This - // also affects the Save dialog by disallowing navigation to these areas. - // An example of a non-file system location is a URL (http://), or a file stored on - // a digital camera that is not mapped to a drive letter. - // This reproduces the behavior of the "classic" Open and Save dialogs. - ret |= Windows.COM_IFileDialog.FOS.FORCEFILESYSTEM; - - return ret; - } - - protected abstract void ProcessVistaFiles(Windows.COM_IFileDialog* dialog, List files); - - private Result SetFileTypes(Windows.COM_IFileDialog* dialog) - { - List filterItems = scope .(); - - // Expected input types - // "Text files (*.txt)|*.txt|All files (*.*)|*.*" - // "Image Files(*.BMP;*.JPG;*.GIF)|*.BMP;*.JPG;*.GIF|All files (*.*)|*.*" - if (!String.IsNullOrEmpty(mFilter)) - { - StringView[] tokens = mFilter.Split!('|'); - if (0 == tokens.Count % 2) - { - // All even numbered tokens should be labels - // Odd numbered tokens are the associated extensions - for (int i = 1; i < tokens.Count; i += 2) - { - Windows.COMDLG_FILTERSPEC ext; - ext.pszSpec = tokens[i].ToScopedNativeWChar!::(); // This may be a semicolon delimited list of extensions (that's ok) - ext.pszName = tokens[i - 1].ToScopedNativeWChar!::(); - filterItems.Add(ext); - } - } - } - - if (filterItems.IsEmpty) - return .Ok; - - Windows.COM_IUnknown.HResult hr = dialog.VT.SetFileTypes(dialog, (uint32)filterItems.Count, filterItems.Ptr); - if (hr.Failed) - return .Err; - - hr = dialog.VT.SetFileTypeIndex(dialog, (uint32)mFilterIndex); - if (hr.Failed) - return .Err; - - return .Ok; - } - } -} -#endif \ No newline at end of file diff --git a/BeefLibs/corlib/src/IO/FileDialog.bf b/BeefLibs/corlib/src/IO/FileDialog.bf index 0ca13890..1f81f2bd 100644 --- a/BeefLibs/corlib/src/IO/FileDialog.bf +++ b/BeefLibs/corlib/src/IO/FileDialog.bf @@ -451,6 +451,130 @@ namespace System.IO return 0; } //TODO: Add ProcessFileNames for validation + + protected abstract Result CreateVistaDialog(); + + private Result TryRunDialogVista(Windows.HWnd hWndOwner) + { + Windows.COM_IFileDialog* dialog; + if (!(CreateVistaDialog() case .Ok(out dialog))) + return .Err; + + OnBeforeVistaDialog(dialog); + dialog.VT.Show(dialog, hWndOwner); + + List files = scope .(); + ProcessVistaFiles(dialog, files); + + DeleteContainerAndItems!(mFileNames); + mFileNames = new String[files.Count]; + files.CopyTo(mFileNames); + + dialog.VT.Release(dialog); + + return .Ok(files.IsEmpty ? .Cancel : .OK); + } + + private void OnBeforeVistaDialog(Windows.COM_IFileDialog* dialog) + { + dialog.VT.SetDefaultExtension(dialog, DefaultExt.ToScopedNativeWChar!()); + + if (mFileNames != null && !mFileNames.IsEmpty) + dialog.VT.SetFileName(dialog, mFileNames[0].ToScopedNativeWChar!()); + + if (!String.IsNullOrEmpty(mInitialDir)) + { + Windows.COM_IShellItem* folderShellItem = null; + Windows.SHCreateItemFromParsingName(mInitialDir.ToScopedNativeWChar!(), null, Windows.COM_IShellItem.sIID, (void**)&folderShellItem); + if (folderShellItem != null) + { + dialog.VT.SetDefaultFolder(dialog, folderShellItem); + dialog.VT.SetFolder(dialog, folderShellItem); + folderShellItem.VT.Release(folderShellItem); + } + } + + dialog.VT.SetTitle(dialog, mTitle.ToScopedNativeWChar!()); + dialog.VT.SetOptions(dialog, GetOptions()); + SetFileTypes(dialog); + } + + private Windows.COM_IFileDialog.FOS GetOptions() + { + const Windows.COM_IFileDialog.FOS BlittableOptions = + Windows.COM_IFileDialog.FOS.OVERWRITEPROMPT + | Windows.COM_IFileDialog.FOS.NOCHANGEDIR + | Windows.COM_IFileDialog.FOS.NOVALIDATE + | Windows.COM_IFileDialog.FOS.ALLOWMULTISELECT + | Windows.COM_IFileDialog.FOS.PATHMUSTEXIST + | Windows.COM_IFileDialog.FOS.FILEMUSTEXIST + | Windows.COM_IFileDialog.FOS.CREATEPROMPT + | Windows.COM_IFileDialog.FOS.NODEREFERENCELINKS; + + const int32 UnexpectedOptions = + (int32)(Windows.OFN_SHOWHELP // If ShowHelp is true, we don't use the Vista Dialog + | Windows.OFN_ENABLEHOOK // These shouldn't be set in options (only set in the flags for the legacy dialog) + | Windows.OFN_ENABLESIZING // These shouldn't be set in options (only set in the flags for the legacy dialog) + | Windows.OFN_EXPLORER); // These shouldn't be set in options (only set in the flags for the legacy dialog) + + Debug.Assert((UnexpectedOptions & mOptions) == 0, "Unexpected FileDialog options"); + + Windows.COM_IFileDialog.FOS ret = (Windows.COM_IFileDialog.FOS)mOptions & BlittableOptions; + + // Force no mini mode for the SaveFileDialog + ret |= Windows.COM_IFileDialog.FOS.DEFAULTNOMINIMODE; + + // Make sure that the Open dialog allows the user to specify + // non-file system locations. This flag will cause the dialog to copy the resource + // to a local cache (Temporary Internet Files), and return that path instead. This + // also affects the Save dialog by disallowing navigation to these areas. + // An example of a non-file system location is a URL (http://), or a file stored on + // a digital camera that is not mapped to a drive letter. + // This reproduces the behavior of the "classic" Open and Save dialogs. + ret |= Windows.COM_IFileDialog.FOS.FORCEFILESYSTEM; + + return ret; + } + + protected abstract void ProcessVistaFiles(Windows.COM_IFileDialog* dialog, List files); + + private Result SetFileTypes(Windows.COM_IFileDialog* dialog) + { + List filterItems = scope .(); + + // Expected input types + // "Text files (*.txt)|*.txt|All files (*.*)|*.*" + // "Image Files(*.BMP;*.JPG;*.GIF)|*.BMP;*.JPG;*.GIF|All files (*.*)|*.*" + if (!String.IsNullOrEmpty(mFilter)) + { + StringView[] tokens = mFilter.Split!('|'); + if (0 == tokens.Count % 2) + { + // All even numbered tokens should be labels + // Odd numbered tokens are the associated extensions + for (int i = 1; i < tokens.Count; i += 2) + { + Windows.COMDLG_FILTERSPEC ext; + ext.pszSpec = tokens[i].ToScopedNativeWChar!::(); // This may be a semicolon delimited list of extensions (that's ok) + ext.pszName = tokens[i - 1].ToScopedNativeWChar!::(); + filterItems.Add(ext); + } + } + } + + if (filterItems.IsEmpty) + return .Ok; + + Windows.COM_IUnknown.HResult hr = dialog.VT.SetFileTypes(dialog, (uint32)filterItems.Count, filterItems.Ptr); + if (hr.Failed) + return .Err; + + hr = dialog.VT.SetFileTypeIndex(dialog, (uint32)mFilterIndex); + if (hr.Failed) + return .Err; + + return .Ok; + } } } #endif \ No newline at end of file From ecdc22920aca30bc778f540e08ac4cfcbcb8b728 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Fri, 17 Dec 2021 08:30:15 -0500 Subject: [PATCH 057/139] Fixed erroneous return type limitations for operators --- IDEHelper/Compiler/BfAutoComplete.cpp | 2 +- IDEHelper/Compiler/BfModule.cpp | 2 +- IDEHelper/Compiler/BfReducer.cpp | 7 ++----- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/IDEHelper/Compiler/BfAutoComplete.cpp b/IDEHelper/Compiler/BfAutoComplete.cpp index aca82e51..d3474719 100644 --- a/IDEHelper/Compiler/BfAutoComplete.cpp +++ b/IDEHelper/Compiler/BfAutoComplete.cpp @@ -1623,7 +1623,7 @@ void BfAutoComplete::CheckIdentifier(BfAstNode* identifierNode, bool isInExpress { "abstract", "base", "class", "const", "delegate", "extern", "enum", "explicit", "extension", "function", - "interface", "in", "internal", "mixin", "namespace", "new", + "interface", "in", "implicit", "internal", "mixin", "namespace", "new", "operator", "out", "override", "params", "private", "protected", "public", "readonly", "ref", "rettype", "return", "scope", "sealed", "static", "struct", "this", "typealias", "using", "virtual", "volatile", "T", "where" diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 1454d2ec..760f6c68 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -14491,7 +14491,7 @@ BfLocalVariable* BfModule::AddLocalVariableDef(BfLocalVariable* localVarDef, boo if ((localVarDef->mNameNode != NULL) && (mCurMethodInstance != NULL)) { bool isClosureProcessing = (mCurMethodState->mClosureState != NULL) && (!mCurMethodState->mClosureState->mCapturing); - if ((!isClosureProcessing) && (mCompiler->mResolvePassData != NULL) && (localVarDef->mNameNode != NULL) && (!mIsComptimeModule)) + if ((!isClosureProcessing) && (mCompiler->mResolvePassData != NULL) && (localVarDef->mNameNode != NULL) && (rootMethodState->mMethodInstance != NULL) && (!mIsComptimeModule)) mCompiler->mResolvePassData->HandleLocalReference(localVarDef->mNameNode, rootMethodState->mMethodInstance->GetOwner()->mTypeDef, rootMethodState->mMethodInstance->mMethodDef, localVarDef->mLocalVarId); } diff --git a/IDEHelper/Compiler/BfReducer.cpp b/IDEHelper/Compiler/BfReducer.cpp index efc75e6d..baa65d07 100644 --- a/IDEHelper/Compiler/BfReducer.cpp +++ b/IDEHelper/Compiler/BfReducer.cpp @@ -5912,12 +5912,9 @@ BfAstNode* BfReducer::ReadTypeMember(BfTokenNode* tokenNode, bool declStarted, i ReplaceNode(tokenNode, operatorDecl); operatorDecl->mOperatorToken = tokenNode; - auto nextIdentifier = ExpectIdentifierAfter(operatorDecl, "type"); - if (nextIdentifier == NULL) - return operatorDecl; - mVisitorPos.mReadPos--; // Backtrack, that's part of our type - auto typeRef = CreateTypeRefAfter(operatorDecl); + if (typeRef == NULL) + return operatorDecl; MEMBER_SET_CHECKED(operatorDecl, mReturnType, typeRef); operatorDecl->mIsConvOperator = true; From 69a597574d106fdf4e9408dc49d786abdada9def Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Fri, 17 Dec 2021 12:56:51 -0500 Subject: [PATCH 058/139] Fixed some struct* constraint checking --- IDEHelper/Compiler/BfModule.cpp | 15 ++++++++------- IDEHelper/Compiler/BfStmtEvaluator.cpp | 4 ++++ IDEHelper/Tests/src/Generics.bf | 23 ++++++++++++++++++++++- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 760f6c68..c2407a3e 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -7787,9 +7787,16 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS } } + if (checkArgType->IsPointer()) + { + auto ptrType = (BfPointerType*)checkArgType; + checkArgType = ptrType->mElementType; + } + if ((genericParamInst->mGenericParamFlags & BfGenericParamFlag_New) != 0) { bool canAlloc = false; + if (auto checkTypeInst = checkArgType->ToTypeInstance()) { if (checkTypeInst->IsObjectOrStruct()) @@ -7857,13 +7864,7 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS } if ((genericParamInst->mInterfaceConstraints.IsEmpty()) && (genericParamInst->mOperatorConstraints.IsEmpty()) && (genericParamInst->mTypeConstraint == NULL)) - return true; - - if (checkArgType->IsPointer()) - { - auto ptrType = (BfPointerType*)checkArgType; - checkArgType = ptrType->mElementType; - } + return true; if (genericParamInst->mTypeConstraint != NULL) { diff --git a/IDEHelper/Compiler/BfStmtEvaluator.cpp b/IDEHelper/Compiler/BfStmtEvaluator.cpp index a3bda91d..e9919b51 100644 --- a/IDEHelper/Compiler/BfStmtEvaluator.cpp +++ b/IDEHelper/Compiler/BfStmtEvaluator.cpp @@ -3925,6 +3925,10 @@ void BfModule::Visit(BfDeleteStatement* deleteStmt) { if (genericParamInst->mGenericParamFlags & (BfGenericParamFlag_Delete | BfGenericParamFlag_Var)) return; + if (genericParamInst->mGenericParamFlags & BfGenericParamFlag_StructPtr) + return; + if ((genericParamInst->mGenericParamFlags & BfGenericParamFlag_Struct) && (checkType->IsPointer())) + return; Fail(StrFormat("Must add 'where %s : delete' constraint to generic parameter to delete generic type '%s'", genericParamInst->GetGenericParamDef()->mName.c_str(), TypeToString(val.mType).c_str()), deleteStmt->mExpression); return; diff --git a/IDEHelper/Tests/src/Generics.bf b/IDEHelper/Tests/src/Generics.bf index 01d420b6..a5999428 100644 --- a/IDEHelper/Tests/src/Generics.bf +++ b/IDEHelper/Tests/src/Generics.bf @@ -23,6 +23,16 @@ namespace Tests { class Generics { + struct StructA : IDisposable + { + int mA = 123; + + public void Dispose() + { + + } + } + class ClassA : IDisposable, LibA.IVal { int LibA.IVal.Val @@ -172,7 +182,7 @@ namespace Tests delete val; } - public static void Alloc2() where T : new, delete, IDisposable, struct + public static void Alloc2() where T : new, IDisposable, struct { alloctype(T) val = new T(); T* val2 = val; @@ -180,6 +190,14 @@ namespace Tests delete val; } + public static void Alloc3() where T : new, IDisposable, struct* + { + T val2 = default; + if (val2 != null) + val2.Dispose(); + delete val2; + } + public class ClassE { public static Self Instance = new ClassE() ~ delete _; @@ -311,6 +329,9 @@ namespace Tests [Test] public static void TestBasics() { + Alloc2(); + Alloc3(); + MethodD(scope => MethodC); List list = scope .(); From 045e706600d3ab9be3aff15772a9fd9998e7cfb6 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Fri, 17 Dec 2021 15:45:53 -0500 Subject: [PATCH 059/139] Added CallerType, CallerTypeName --- BeefLibs/corlib/src/Compiler.bf | 6 ++++++ IDEHelper/Compiler/BfExprEvaluator.cpp | 20 +++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/BeefLibs/corlib/src/Compiler.bf b/BeefLibs/corlib/src/Compiler.bf index 3030c444..3be28ff7 100644 --- a/BeefLibs/corlib/src/Compiler.bf +++ b/BeefLibs/corlib/src/Compiler.bf @@ -217,6 +217,12 @@ namespace System [LinkName("#CallerFileDir")] public static extern String CallerFileDir; + [LinkName("#CallerType")] + public static extern Type CallerType; + + [LinkName("#CallerTypeName")] + public static extern String CallerTypeName; + [LinkName("#CallerMemberName")] public static extern String CallerMemberName; diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index a7750009..5db8dfee 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -6973,7 +6973,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu filePath = mModule->mCurFilePosition.mFileInstance->mParser->mFileName; argValue = BfTypedValue(mModule->GetStringObjectValue(filePath), mModule->ResolveTypeDef(mModule->mCompiler->mStringTypeDef)); - } + } else if (strcmp(globalVar->mName, "#CallerFileName") == 0) { String filePath = ""; @@ -6990,6 +6990,24 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu argValue = BfTypedValue(mModule->GetStringObjectValue(GetFileDir(filePath)), mModule->ResolveTypeDef(mModule->mCompiler->mStringTypeDef)); } + else if (strcmp(globalVar->mName, "#CallerTypeName") == 0) + { + String typeName = ""; + if (mModule->mCurTypeInstance != NULL) + typeName = mModule->TypeToString(mModule->mCurTypeInstance); + argValue = BfTypedValue(mModule->GetStringObjectValue(typeName), + mModule->ResolveTypeDef(mModule->mCompiler->mStringTypeDef)); + } + else if (strcmp(globalVar->mName, "#CallerType") == 0) + { + auto typeType = mModule->ResolveTypeDef(mModule->mCompiler->mTypeTypeDef); + BfType* type = mModule->mCurTypeInstance; + if (type != NULL) + { + mModule->AddDependency(type, mModule->mCurTypeInstance, BfDependencyMap::DependencyFlag_ExprTypeReference); + argValue = BfTypedValue(mModule->CreateTypeDataRef(type), typeType); + } + } else if (strcmp(globalVar->mName, "#CallerMemberName") == 0) { String memberName = ""; From 76e94d1cdcadee8debc452789674e90c3e71076b Mon Sep 17 00:00:00 2001 From: unknown <81806010+marsej@users.noreply.github.com> Date: Sat, 18 Dec 2021 20:29:15 +0200 Subject: [PATCH 060/139] Add CommentLines CommentBlocks and replace ToggleComment --- IDE/src/ui/SourceEditWidgetContent.bf | 167 ++++++++++++++++++-------- 1 file changed, 120 insertions(+), 47 deletions(-) diff --git a/IDE/src/ui/SourceEditWidgetContent.bf b/IDE/src/ui/SourceEditWidgetContent.bf index bb06a5c2..7650453c 100644 --- a/IDE/src/ui/SourceEditWidgetContent.bf +++ b/IDE/src/ui/SourceEditWidgetContent.bf @@ -2160,9 +2160,9 @@ namespace IDE.ui return true; } - public bool ToggleComment(bool? doComment = null) + public bool CommentBlock() { - if (gApp.mSettings.mEditorSettings.mToggleCommentAlt) return ToggleCommentAlt(doComment); + bool? doComment = true; if (CheckReadOnly()) return false; @@ -2175,11 +2175,11 @@ namespace IDE.ui mSelection = .(CursorTextPos, cursorEndPos); } - if ((HasSelection()) && (mSelection.Value.Length > 1)) - { + if ((HasSelection()) && (mSelection.Value.Length > 1)) + { var startLineAndCol = CursorLineAndColumn; - UndoBatchStart undoBatchStart = new UndoBatchStart("embeddedToggleComment"); + UndoBatchStart undoBatchStart = new UndoBatchStart("embeddedCommentBlock"); mData.mUndoManager.Add(undoBatchStart); mData.mUndoManager.Add(new SetCursorAction(this)); @@ -2202,20 +2202,7 @@ namespace IDE.ui int firstCharPos = minPos + (startLen - afterTrimStart); int lastCharPos = maxPos - (afterTrimStart - afterTrimEnd); - if ((doComment != true) && (trimmedStr.StartsWith("/*"))) - { - if (trimmedStr.EndsWith("*/")) - { - mSelection = EditSelection(firstCharPos, firstCharPos + 2); - DeleteChar(); - mSelection = EditSelection(lastCharPos - 4, lastCharPos - 2); - DeleteChar(); - - if (doComment != null) - mSelection = EditSelection(firstCharPos, lastCharPos - 4); - } - } - else if (doComment != false) + if (doComment != false) { CursorTextPos = firstCharPos; InsertAtCursor("/*"); @@ -2234,17 +2221,109 @@ namespace IDE.ui if (doComment == null) mSelection = null; - return true; - } + return true; + } return false; } - - public bool ToggleCommentAlt(bool? doComment = null) + + public bool CommentLines() + { + bool? doComment = true; + if (CheckReadOnly()) + return false; + bool noStar = false; + + var startLineAndCol = CursorLineAndColumn; + if ((!HasSelection()) && (doComment != null)) + { + CursorToLineEnd(); + int cursorEndPos = CursorTextPos; + + mSelection = .(CursorTextPos, cursorEndPos); + noStar = true; + } + + + if (true || (HasSelection()) && (mSelection.Value.Length > 0)) + { + //int cursorEndPos = CursorTextPos; + + // set selection to begin from line start + int lineIdx; + int lineChar; + GetLineCharAtIdx(mSelection.GetValueOrDefault().MinPos,out lineIdx, out lineChar); + MoveCursorTo(lineIdx, 0); + mSelection = .(CursorTextPos, mSelection.GetValueOrDefault().MaxPos); + + UndoBatchStart undoBatchStart = new UndoBatchStart("embeddedCommentLines"); + mData.mUndoManager.Add(undoBatchStart); + + mData.mUndoManager.Add(new SetCursorAction(this)); + + int minPos = mSelection.GetValueOrDefault().MinPos; + int maxPos = mSelection.GetValueOrDefault().MaxPos; + mSelection = null; + + var str = scope String(); + ExtractString(minPos, maxPos - minPos, str); + var trimmedStr = scope String(); + trimmedStr.Append(str); + int32 startLen = (int32)trimmedStr.Length; + trimmedStr.TrimStart(); + int32 afterTrimStart = (int32)trimmedStr.Length; + trimmedStr.TrimEnd(); + //int32 afterTrimEnd = (int32)trimmedStr.Length; + trimmedStr.Append('\n'); + + int firstCharPos = minPos + (startLen - afterTrimStart); + //int lastCharPos = maxPos - (afterTrimStart - afterTrimEnd); + + int q = 0; + //var nc = trimmedStr.Count('\n'); + + if (doComment != false) + { + while (firstCharPos >= 0 && SafeGetChar(firstCharPos) != '\n') + { + firstCharPos--; + } + bool blank=true; + for (int i = firstCharPos + 1; i < maxPos + q; i++) + { + blank=false; + CursorTextPos = i; // needed to add i < maxPos + q; for this to work with InsertAtCursor + InsertAtCursor("//"); q++; q++; + + while (SafeGetChar(i) != '\n' && i < maxPos + q) + { + i++; + } + } + mSelection = EditSelection(minPos, maxPos + q); + } + + + if (undoBatchStart != null) + mData.mUndoManager.Add(undoBatchStart.mBatchEnd); + + CursorLineAndColumn = startLineAndCol; + + if (doComment == null) + mSelection = null; + + return true; + } + + //return false; + } + + public bool ToggleComment(bool? doComment = null) { if (CheckReadOnly()) return false; bool noStar = false; + var startLineAndCol = CursorLineAndColumn; if ((!HasSelection()) && (doComment != null)) { CursorToLineEnd(); @@ -2256,7 +2335,13 @@ namespace IDE.ui if ((HasSelection()) && (mSelection.Value.Length > 0)) { - var startLineAndCol = CursorLineAndColumn; + + int lineIdx; + int lineChar; + GetLineCharAtIdx(mSelection.GetValueOrDefault().MinPos,out lineIdx, out lineChar); + MoveCursorTo(lineIdx, 0); + mSelection = .(CursorTextPos, mSelection.GetValueOrDefault().MaxPos); + UndoBatchStart undoBatchStart = new UndoBatchStart("embeddedToggleComment"); mData.mUndoManager.Add(undoBatchStart); @@ -2296,11 +2381,11 @@ namespace IDE.ui return false; // not sure if this should be false in blank/only whitespace selection case } - else if ((doComment != true) && (trimmedStr.Contains("//"))) + else if ((doComment != true) && (trimmedStr.StartsWith("//"))) { - for (int i = firstCharPos; i < lastCharPos - 1; i++) + for (int i = firstCharPos; i <= lastCharPos; i++) { - if (minPos == 0 || (minPos>0 && SafeGetChar(i - 1) == '\n' || SafeGetChar(i - 1) == '\t')) + if ((minPos == 0 && i==0) || (minPos>=0 && SafeGetChar(i - 1) == '\n' || SafeGetChar(i - 1) == '\t')) if (SafeGetChar(i - 0) == '/' && SafeGetChar(i + 1) == '/') { mSelection = EditSelection(i - 0, i + 2); @@ -2312,7 +2397,11 @@ namespace IDE.ui } } } - mSelection = EditSelection(minPos, lastCharPos); + + CursorToLineEnd(); + int cursorEndPos = CursorTextPos; + mSelection = .(minPos, cursorEndPos); + } else if ((doComment != true) && (trimmedStr.StartsWith("/*"))) { @@ -2327,7 +2416,8 @@ namespace IDE.ui mSelection = EditSelection(firstCharPos, lastCharPos - 4); } } - else if (doComment != false && nc<=1 && minPos >=0 && (SafeGetChar(minPos-1) != ' ' && SafeGetChar(minPos-1) != '\t') && SafeGetChar(minPos-1) != '\n') + else if (doComment != false && minPos >=0 && ((nc<=1 && (SafeGetChar(minPos-1) != ' ' && SafeGetChar(minPos-1) != '\t') && SafeGetChar(minPos-1) != '\n') + || nc>=1 && (SafeGetChar(maxPos-1) != ' ' && SafeGetChar(maxPos-1) != '\t') && SafeGetChar(maxPos-1) != '\n')) { //if selection is from beginning of the line then we want to use // comment, that's why the check for line count and ' ' and tab CursorTextPos = firstCharPos; if (noStar) { @@ -2344,23 +2434,6 @@ namespace IDE.ui if (!noStar && doComment != null) mSelection = EditSelection(firstCharPos, lastCharPos + 4); } - else if (doComment != false && nc>=1 && minPos >0 && (SafeGetChar(maxPos-1) != ' ' && SafeGetChar(maxPos-1) != '\t') && SafeGetChar(maxPos-1) != '\n') - { - CursorTextPos = firstCharPos; - if (noStar) { - CursorTextPos = minPos; - - InsertAtCursor("//"); //goes here if no selection - } - else - { - InsertAtCursor("/*"); - CursorTextPos = lastCharPos + 2; - InsertAtCursor("*/"); - } - if (!noStar && doComment != null) - mSelection = EditSelection(firstCharPos, lastCharPos + 4); - } else if (doComment != false) { while (firstCharPos >= 0 && SafeGetChar(firstCharPos) != '\n') @@ -2394,7 +2467,7 @@ namespace IDE.ui return false; } - + public void DeleteAllRight() { int startPos; From 5a5a3b0f54fbdb97589addd73d3641a6df09f9c4 Mon Sep 17 00:00:00 2001 From: unknown <81806010+marsej@users.noreply.github.com> Date: Sat, 18 Dec 2021 20:36:46 +0200 Subject: [PATCH 061/139] Add the new commands to menu --- IDE/src/Commands.bf | 2 ++ IDE/src/IDEApp.bf | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/IDE/src/Commands.bf b/IDE/src/Commands.bf index f0b2de76..c7eeb2cf 100644 --- a/IDE/src/Commands.bf +++ b/IDE/src/Commands.bf @@ -194,6 +194,8 @@ namespace IDE Add("Close Document", new () => { gApp.[Friend]TryCloseCurrentDocument(); }); Add("Close Panel", new () => { gApp.[Friend]TryCloseCurrentPanel(); }); Add("Close Workspace", new => gApp.[Friend]Cmd_CloseWorkspaceAndSetupNew); + Add("Comment Block", new => gApp.[Friend]CommentBlock); + Add("Comment Lines", new => gApp.[Friend]CommentLines); Add("Comment Selection", new => gApp.[Friend]CommentSelection); Add("Compile File", new => gApp.Cmd_CompileFile); Add("Debug All Tests", new () => { gApp.[Friend]RunTests(true, true); }); diff --git a/IDE/src/IDEApp.bf b/IDE/src/IDEApp.bf index 0131b705..f6dbf6c4 100644 --- a/IDE/src/IDEApp.bf +++ b/IDE/src/IDEApp.bf @@ -2424,6 +2424,22 @@ namespace IDE sewc.DuplicateLine(); } + [IDECommand] + void CommentBlock() + { + var sewc = GetActiveSourceEditWidgetContent(); + if (sewc != null) + sewc.CommentBlock(); + } + + [IDECommand] + void CommentLines() + { + var sewc = GetActiveSourceEditWidgetContent(); + if (sewc != null) + sewc.CommentLines(); + } + [IDECommand] void CommentSelection() { @@ -5386,6 +5402,8 @@ namespace IDE advancedEditMenu.AddMenuItem(null); AddMenuItem(advancedEditMenu, "Make Uppercase", "Make Uppercase"); AddMenuItem(advancedEditMenu, "Make Lowercase", "Make Lowercase"); + AddMenuItem(advancedEditMenu, "Comment Block", "Comment Block"); + AddMenuItem(advancedEditMenu, "Comment Lines", "Comment Lines"); AddMenuItem(advancedEditMenu, "Comment Selection", "Comment Selection"); AddMenuItem(advancedEditMenu, "Uncomment Selection", "Uncomment Selection"); AddMenuItem(advancedEditMenu, "Reformat Document", "Reformat Document"); From 25e09590183104f455a5e88c9fe0dfad0e0760d4 Mon Sep 17 00:00:00 2001 From: unknown <81806010+marsej@users.noreply.github.com> Date: Sat, 18 Dec 2021 20:38:05 +0200 Subject: [PATCH 062/139] Add new key-defaults --- IDE/src/Settings.bf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/IDE/src/Settings.bf b/IDE/src/Settings.bf index d0012c42..d5e7536f 100644 --- a/IDE/src/Settings.bf +++ b/IDE/src/Settings.bf @@ -756,6 +756,8 @@ namespace IDE Add("Cancel Build", "Ctrl+Break"); Add("Close Document", "Ctrl+W"); Add("Compile File", "Ctrl+F7"); + Add("Comment Block", "Ctrl+K, Ctrl+B"); + Add("Comment Lines", "Ctrl+K, Ctrl+L"); Add("Comment Selection", "Ctrl+K, Ctrl+C"); Add("Duplicate Line", "Ctrl+D"); Add("Find Class", "Alt+Shift+L"); From f1652dd1aaa3c835e03b5a3859ef26d37b3e9a1b Mon Sep 17 00:00:00 2001 From: unknown <81806010+marsej@users.noreply.github.com> Date: Sat, 18 Dec 2021 20:45:02 +0200 Subject: [PATCH 063/139] Remove mToggleCommentAlt setting --- IDE/src/Settings.bf | 3 --- 1 file changed, 3 deletions(-) diff --git a/IDE/src/Settings.bf b/IDE/src/Settings.bf index d5e7536f..f3a2ca1d 100644 --- a/IDE/src/Settings.bf +++ b/IDE/src/Settings.bf @@ -625,7 +625,6 @@ namespace IDE public FileRecoveryKind mEnableFileRecovery = .Yes; public bool mFormatOnSave = false; public bool mSyncWithWorkspacePanel = false; - public bool mToggleCommentAlt = false; public void Serialize(StructuredData sd) { @@ -651,7 +650,6 @@ namespace IDE sd.Add("EnableFileRecovery", mEnableFileRecovery); sd.Add("FormatOnSave", mFormatOnSave); sd.Add("SyncWithWorkspacePanel", mSyncWithWorkspacePanel); - sd.Add("ToggleCommentAlt", mToggleCommentAlt); } public void Deserialize(StructuredData sd) @@ -681,7 +679,6 @@ namespace IDE sd.GetEnum("EnableFileRecovery", ref mEnableFileRecovery); sd.Get("FormatOnSave", ref mFormatOnSave); sd.Get("SyncWithWorkspacePanel", ref mSyncWithWorkspacePanel); - sd.Get("ToggleCommentAlt", ref mToggleCommentAlt); } public void SetDefaults() From 28ad51fbfbc6117b18d4f4ff2032ee1367a0a734 Mon Sep 17 00:00:00 2001 From: unknown <81806010+marsej@users.noreply.github.com> Date: Sat, 18 Dec 2021 20:51:04 +0200 Subject: [PATCH 064/139] fix some whitespaces --- IDE/src/ui/SourceEditWidgetContent.bf | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/IDE/src/ui/SourceEditWidgetContent.bf b/IDE/src/ui/SourceEditWidgetContent.bf index 7650453c..64862c77 100644 --- a/IDE/src/ui/SourceEditWidgetContent.bf +++ b/IDE/src/ui/SourceEditWidgetContent.bf @@ -2244,11 +2244,8 @@ namespace IDE.ui noStar = true; } - if (true || (HasSelection()) && (mSelection.Value.Length > 0)) { - //int cursorEndPos = CursorTextPos; - // set selection to begin from line start int lineIdx; int lineChar; @@ -2280,7 +2277,6 @@ namespace IDE.ui //int lastCharPos = maxPos - (afterTrimStart - afterTrimEnd); int q = 0; - //var nc = trimmedStr.Count('\n'); if (doComment != false) { @@ -2303,7 +2299,6 @@ namespace IDE.ui mSelection = EditSelection(minPos, maxPos + q); } - if (undoBatchStart != null) mData.mUndoManager.Add(undoBatchStart.mBatchEnd); @@ -2323,6 +2318,7 @@ namespace IDE.ui if (CheckReadOnly()) return false; bool noStar = false; + var startLineAndCol = CursorLineAndColumn; if ((!HasSelection()) && (doComment != null)) { @@ -2335,10 +2331,9 @@ namespace IDE.ui if ((HasSelection()) && (mSelection.Value.Length > 0)) { - int lineIdx; int lineChar; - GetLineCharAtIdx(mSelection.GetValueOrDefault().MinPos,out lineIdx, out lineChar); + GetLineCharAtIdx(mSelection.GetValueOrDefault().MinPos, out lineIdx, out lineChar); MoveCursorTo(lineIdx, 0); mSelection = .(CursorTextPos, mSelection.GetValueOrDefault().MaxPos); @@ -2385,7 +2380,7 @@ namespace IDE.ui { for (int i = firstCharPos; i <= lastCharPos; i++) { - if ((minPos == 0 && i==0) || (minPos>=0 && SafeGetChar(i - 1) == '\n' || SafeGetChar(i - 1) == '\t')) + if ((minPos == 0 && i == 0) || (minPos>=0 && SafeGetChar(i - 1) == '\n' || SafeGetChar(i - 1) == '\t')) if (SafeGetChar(i - 0) == '/' && SafeGetChar(i + 1) == '/') { mSelection = EditSelection(i - 0, i + 2); @@ -2416,8 +2411,8 @@ namespace IDE.ui mSelection = EditSelection(firstCharPos, lastCharPos - 4); } } - else if (doComment != false && minPos >=0 && ((nc<=1 && (SafeGetChar(minPos-1) != ' ' && SafeGetChar(minPos-1) != '\t') && SafeGetChar(minPos-1) != '\n') - || nc>=1 && (SafeGetChar(maxPos-1) != ' ' && SafeGetChar(maxPos-1) != '\t') && SafeGetChar(maxPos-1) != '\n')) + else if (doComment != false && minPos >=0 && ((nc <= 1 && (SafeGetChar(minPos-1) != ' ' && SafeGetChar(minPos-1) != '\t') && SafeGetChar(minPos-1) != '\n') + || nc >= 1 && (SafeGetChar(maxPos-1) != ' ' && SafeGetChar(maxPos-1) != '\t') && SafeGetChar(maxPos-1) != '\n')) { //if selection is from beginning of the line then we want to use // comment, that's why the check for line count and ' ' and tab CursorTextPos = firstCharPos; if (noStar) { From 77db22d0951ff3ced2fbc26be11fc400056d6ad9 Mon Sep 17 00:00:00 2001 From: unknown <81806010+marsej@users.noreply.github.com> Date: Sat, 18 Dec 2021 22:17:46 +0200 Subject: [PATCH 065/139] Remove mToggleCommentAlt from SettingsDialog --- IDE/src/ui/SettingsDialog.bf | 1 - 1 file changed, 1 deletion(-) diff --git a/IDE/src/ui/SettingsDialog.bf b/IDE/src/ui/SettingsDialog.bf index 7f602893..ca52440c 100644 --- a/IDE/src/ui/SettingsDialog.bf +++ b/IDE/src/ui/SettingsDialog.bf @@ -126,7 +126,6 @@ namespace IDE.ui AddPropertiesItem(category, "Enable File Recovery", "mEnableFileRecovery"); AddPropertiesItem(category, "Format on Save", "mFormatOnSave"); AddPropertiesItem(category, "Sync with Workspace Panel", "mSyncWithWorkspacePanel"); - AddPropertiesItem(category, "Toggle comment alternate style", "mToggleCommentAlt"); category.Open(true, true); } From b8e07788073505aa199593ecf4ea790a0b9a68cb Mon Sep 17 00:00:00 2001 From: unknown <81806010+marsej@users.noreply.github.com> Date: Sun, 19 Dec 2021 04:18:57 +0200 Subject: [PATCH 066/139] Delay ShowWindow until after first render --- BeefLibs/SDL2/src/SDLApp.bf | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/BeefLibs/SDL2/src/SDLApp.bf b/BeefLibs/SDL2/src/SDLApp.bf index 01535fe8..65c042d4 100644 --- a/BeefLibs/SDL2/src/SDLApp.bf +++ b/BeefLibs/SDL2/src/SDLApp.bf @@ -117,12 +117,8 @@ namespace SDL2 SDL.EventState(.JoyDeviceAdded, .Disable); SDL.EventState(.JoyDeviceRemoved, .Disable); - mWindow = SDL.CreateWindow(mTitle, .Undefined, .Undefined, mWidth, mHeight, .Hidden); + mWindow = SDL.CreateWindow(mTitle, .Undefined, .Undefined, mWidth, mHeight, .Hidden); // Initially hide window mRenderer = SDL.CreateRenderer(mWindow, -1, .Accelerated); - SDL.ShowWindow(mWindow); - SDL.SetRenderDrawColor(mRenderer, 0, 0, 0, 255); - SDL.RenderClear(mRenderer); - SDL.RenderPresent(mRenderer); mScreen = SDL.GetWindowSurface(mWindow); SDLImage.Init(.PNG | .JPG); mHasAudio = SDLMixer.OpenAudio(44100, SDLMixer.MIX_DEFAULT_FORMAT, 2, 4096) >= 0; @@ -249,7 +245,9 @@ namespace SDL2 if (curPhysTickCount == 0) { // Initial render - Render(); + Render(); + // Show initially hidden window, mitigates white flash on slow startups + SDL.ShowWindow(mWindow); } else { From ce4b6e04de2b68d4692be6487f8f00f3440bffb9 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 20 Dec 2021 09:39:39 -0500 Subject: [PATCH 067/139] Support for comptime file IO and process creation --- BeefLibs/corlib/src/Compiler.bf | 17 + BeefLibs/corlib/src/Diagnostics/Debug.bf | 19 + BeefLibs/corlib/src/OperatingSystem.bf | 3 + BeefySysLib/platform/win/Platform.cpp | 6 + BeefySysLib/util/String.h | 12 +- IDE/src/Compiler/BfSystem.bf | 8 +- IDE/src/IDEApp.bf | 13 + IDEHelper/Compiler/BfCompiler.cpp | 2 +- IDEHelper/Compiler/BfContext.cpp | 73 +++- IDEHelper/Compiler/BfExprEvaluator.cpp | 6 +- IDEHelper/Compiler/BfModule.cpp | 2 +- IDEHelper/Compiler/BfModuleTypeUtils.cpp | 17 +- IDEHelper/Compiler/BfResolvedTypeUtils.h | 18 +- IDEHelper/Compiler/BfSystem.cpp | 3 +- IDEHelper/Compiler/BfSystem.h | 1 + IDEHelper/Compiler/CeMachine.cpp | 489 +++++++++++++++++++++-- IDEHelper/Compiler/CeMachine.h | 119 +++++- IDEHelper/Tests/Test0.txt | 2 + IDEHelper/Tests/src/Comptime.bf | 5 + 19 files changed, 726 insertions(+), 89 deletions(-) create mode 100644 IDEHelper/Tests/Test0.txt diff --git a/BeefLibs/corlib/src/Compiler.bf b/BeefLibs/corlib/src/Compiler.bf index 3be28ff7..290c821a 100644 --- a/BeefLibs/corlib/src/Compiler.bf +++ b/BeefLibs/corlib/src/Compiler.bf @@ -2,6 +2,7 @@ using System.Reflection; using System.Diagnostics; using System.Collections; using System.Security.Cryptography; +using System.IO; namespace System { @@ -306,5 +307,21 @@ namespace System if (Compiler.IsComptime) Comptime_EmitMixin(text); } + + [Comptime] + public static Span ReadBinary(StringView path) + { + List data = scope .(); + File.ReadAll(path, data); + return data; + } + + [Comptime] + public static String ReadText(StringView path) + { + String data = scope .(); + File.ReadAllText(path, data); + return data; + } } } diff --git a/BeefLibs/corlib/src/Diagnostics/Debug.bf b/BeefLibs/corlib/src/Diagnostics/Debug.bf index e7a2a554..7ab33151 100644 --- a/BeefLibs/corlib/src/Diagnostics/Debug.bf +++ b/BeefLibs/corlib/src/Diagnostics/Debug.bf @@ -106,5 +106,24 @@ namespace System.Diagnostics if (gIsDebuggerPresent) Break(); } + + public static void WriteMemory(Span mem) + { + String str = scope .(); + for (int i < mem.Length) + { + if ((i != 0) && (i % 16 == 0)) + str.Append('\n'); + str.AppendF($" {mem.[Friend]mPtr[i]:X2}"); + } + str.Append('\n'); + Write(str); + } + + public static void WriteMemory(T result) + { +#unwarn + WriteMemory(.((.)&result, sizeof(T))); + } } } diff --git a/BeefLibs/corlib/src/OperatingSystem.bf b/BeefLibs/corlib/src/OperatingSystem.bf index eb1d578b..117c6819 100644 --- a/BeefLibs/corlib/src/OperatingSystem.bf +++ b/BeefLibs/corlib/src/OperatingSystem.bf @@ -118,6 +118,9 @@ namespace System public this() { + if (Compiler.IsComptime) + return; + #if BF_PLATFORM_WINDOWS bool isWinSrv() { diff --git a/BeefySysLib/platform/win/Platform.cpp b/BeefySysLib/platform/win/Platform.cpp index e8a91d1e..9ba9e69b 100644 --- a/BeefySysLib/platform/win/Platform.cpp +++ b/BeefySysLib/platform/win/Platform.cpp @@ -2909,6 +2909,12 @@ BFP_EXPORT intptr BFP_CALLTYPE BfpFile_Read(BfpFile* file, void* buffer, intptr //TODO: this doesn't set file stream location. It only works for streams like pipes, sockets, etc if (::ReadFileEx(file->mHandle, buffer, (uint32)size, &overlapped, OverlappedReadComplete)) { + if (file->mAsyncData == NULL) + { + OUTRESULT(BfpFileResult_InvalidParameter); + return 0; + } + if (!file->mAsyncData->WaitAndResetEvent(timeoutMS)) { ::CancelIoEx(file->mHandle, &overlapped); diff --git a/BeefySysLib/util/String.h b/BeefySysLib/util/String.h index 3d7d8299..e30d9679 100644 --- a/BeefySysLib/util/String.h +++ b/BeefySysLib/util/String.h @@ -622,7 +622,17 @@ public: str.mLength = (int_strsize)strlen(charPtr); str.mAllocSizeAndFlags = str.mLength | StrPtrFlag; return str; - } + } + + static StringImpl MakeRef(const char* charPtr, intptr length) + { + StringImpl str; + // This is just a ref - called when we pass a literal to a method (for example) + str.mPtr = (char*)charPtr; + str.mLength = (int_strsize)length; + str.mAllocSizeAndFlags = str.mLength | StrPtrFlag; + return str; + } static StringImpl MakeRef(const StringView& strView) { diff --git a/IDE/src/Compiler/BfSystem.bf b/IDE/src/Compiler/BfSystem.bf index 0d7b93ee..cd1b057e 100644 --- a/IDE/src/Compiler/BfSystem.bf +++ b/IDE/src/Compiler/BfSystem.bf @@ -51,7 +51,7 @@ namespace IDE.Compiler static extern char8* BfSystem_GetNamespaceSearch(void* bfSystem, char8* typeName, void* project); [CallingConvention(.Stdcall), CLink] - static extern void* BfSystem_CreateProject(void* bfSystem, char8* projectName); + static extern void* BfSystem_CreateProject(void* bfSystem, char8* projectName, char8* projectDir); [CallingConvention(.Stdcall), CLink] static extern void BfSystem_ClearTypeOptions(void* bfSystem); @@ -142,7 +142,7 @@ namespace IDE.Compiler { using (mMonitor.Enter()) { - var bfProject = CreateProject(project.mProjectName); + var bfProject = CreateProject(project.mProjectName, project.mProjectDir); mProjectMap[project] = bfProject; } } @@ -188,10 +188,10 @@ namespace IDE.Compiler outNamespaceSearch.Append(namespaceSearch); } - public BfProject CreateProject(String projectName) + public BfProject CreateProject(String projectName, String projectDir) { BfProject project = new BfProject(); - project.mNativeBfProject = BfSystem_CreateProject(mNativeBfSystem, projectName); + project.mNativeBfProject = BfSystem_CreateProject(mNativeBfSystem, projectName, projectDir); return project; } diff --git a/IDE/src/IDEApp.bf b/IDE/src/IDEApp.bf index 0131b705..14271dd5 100644 --- a/IDE/src/IDEApp.bf +++ b/IDE/src/IDEApp.bf @@ -9167,6 +9167,13 @@ namespace IDE bool doCompile = false; if (lastCompileHadMessages) doCompile = true; + + bool needsComptime = true; + for (var project in mWorkspace.mProjects) + { + //Set needsComptime + } + if ((!workspaceOptions.mIncrementalBuild) && (!lastCompileHadMessages)) { tryQueueFiles = false; @@ -9177,6 +9184,9 @@ namespace IDE } } + if (needsComptime) + tryQueueFiles = true; + if (hotProject != null) { mWorkspace.mHadHotCompileSinceLastFullCompile = true; @@ -9210,6 +9220,9 @@ namespace IDE } } + if (needsComptime) + doCompile = true; + if (!success) { bfCompiler.QueueDeletePassInstance(passInstance); diff --git a/IDEHelper/Compiler/BfCompiler.cpp b/IDEHelper/Compiler/BfCompiler.cpp index 9be06ac6..f05743fa 100644 --- a/IDEHelper/Compiler/BfCompiler.cpp +++ b/IDEHelper/Compiler/BfCompiler.cpp @@ -2927,7 +2927,7 @@ void BfCompiler::GenerateDynCastData() void BfCompiler::UpdateRevisedTypes() { - BfLogSysM("UpdateRevisedTypes\n"); + BfLogSysM("BfCompiler::UpdateRevisedTypes\n"); BP_ZONE("BfCompiler::UpdateRevisedTypes"); // See if we have any name conflicts and remove those diff --git a/IDEHelper/Compiler/BfContext.cpp b/IDEHelper/Compiler/BfContext.cpp index f338c2f1..81bd8c6a 100644 --- a/IDEHelper/Compiler/BfContext.cpp +++ b/IDEHelper/Compiler/BfContext.cpp @@ -26,6 +26,7 @@ #include "BfSourceClassifier.h" #include "BfAutoComplete.h" #include "BfResolvePass.h" +#include "CeMachine.h" #pragma warning(pop) @@ -1850,6 +1851,7 @@ void BfContext::PreUpdateRevisedTypes() void BfContext::UpdateRevisedTypes() { BP_ZONE("BfContext::UpdateRevisedTypes"); + BfLogSysM("BfContext::UpdateRevisedTypes\n"); int wantPtrSize; if ((mCompiler->mOptions.mMachineType == BfMachineType_x86) | @@ -1889,6 +1891,9 @@ void BfContext::UpdateRevisedTypes() bool wantsDebugInfo = (mCompiler->mOptions.mEmitDebugInfo); Array defStateChangedQueue; + Array defEmitParentCheckQueue; + + Dictionary lastWriteTimeMap; // Do primary 'rebuild' scan for (auto type : mResolvedTypes) @@ -1917,20 +1922,8 @@ void BfContext::UpdateRevisedTypes() auto typeDef = typeInst->mTypeDef; - if (typeDef->mEmitParent != NULL) - { - if (typeDef->mDefState == BfTypeDef::DefState_Deleted) - { - typeInst->mTypeDef = typeDef->mEmitParent; - } - else - { - auto emitTypeDef = typeDef; - typeDef = typeDef->mEmitParent; - if (typeDef->mNextRevision != NULL) - emitTypeDef->mDefState = BfTypeDef::DefState_EmittedDirty; - } - } + if (typeDef->mEmitParent != NULL) + defEmitParentCheckQueue.Add(typeInst); if (typeDef->mProject->mDisabled) { @@ -1939,7 +1932,7 @@ void BfContext::UpdateRevisedTypes() } typeInst->mRebuildFlags = BfTypeRebuildFlag_None; - + if (typeDef->mIsPartial) { // This was a type that wasn't marked as partial before but now it is, so it doesn't need its own typedef @@ -1948,6 +1941,31 @@ void BfContext::UpdateRevisedTypes() continue; } + if (typeInst->mCeTypeInfo != NULL) + { + bool changed = false; + + for (auto& kv : typeInst->mCeTypeInfo->mRebuildMap) + { + if (kv.mKey.mKind == CeRebuildKey::Kind_File) + { + String* keyPtr = NULL; + uint64* valuePtr = NULL; + if (lastWriteTimeMap.TryAdd(kv.mKey.mString, &keyPtr, &valuePtr)) + { + *valuePtr = BfpFile_GetTime_LastWrite(kv.mKey.mString.c_str()); + } + if (*valuePtr != kv.mValue.mInt) + changed = true; + } + } + + if (changed) + { + RebuildType(typeInst); + } + } + if ((typeInst->mHotTypeData != NULL) && (!mCompiler->IsHotCompile())) { if (typeInst->mHotTypeData->GetLatestVersion()->mDeclHotCompileIdx != 0) @@ -2042,6 +2060,31 @@ void BfContext::UpdateRevisedTypes() } } + for (auto typeInst : defEmitParentCheckQueue) + { + if (typeInst->IsDeleting()) + continue; + auto typeDef = typeInst->mTypeDef; + if (typeDef->mEmitParent != NULL) + { + if (typeDef->mDefState == BfTypeDef::DefState_Deleted) + { + BfLogSysM("Type %p typeDef %p deleted, setting to emitParent %p\n", typeInst, typeDef, typeDef->mEmitParent); + typeInst->mTypeDef = typeDef->mEmitParent; + } + else + { + auto emitTypeDef = typeDef; + typeDef = typeDef->mEmitParent; + if (typeDef->mNextRevision != NULL) + { + BfLogSysM("Type %p typeDef %p emitparent %p has next revision, setting emittedDirty\n", typeInst, emitTypeDef, typeDef); + emitTypeDef->mDefState = BfTypeDef::DefState_EmittedDirty; + } + } + } + } + // { AutoCrit autoCrit(mSystem->mDataLock); diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 5db8dfee..265031d5 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -14543,8 +14543,10 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs { if (typeInstance->IsObject()) { + bool hasRealtimeLeakCheck = (mModule->mCompiler->mOptions.mEnableRealtimeLeakCheck) && (!IsComptime()); + bool wantsCtorClear = true; - if (mModule->mCompiler->mOptions.mEnableRealtimeLeakCheck) + if (hasRealtimeLeakCheck) { // Dbg_ObjectAlloc clears internally so we don't need to call CtorClear for those if ((!isStackAlloc) && (!allocTarget.mCustomAllocator) && (allocTarget.mScopedInvocationTarget == NULL)) @@ -14566,7 +14568,7 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs } } - if ((!mModule->mIsComptimeModule) && (isStackAlloc) && (mModule->mCompiler->mOptions.mEnableRealtimeLeakCheck)) + if ((!mModule->mIsComptimeModule) && (isStackAlloc) && (hasRealtimeLeakCheck)) { BfMethodInstance* markMethod = mModule->GetRawMethodByName(mModule->mContext->mBfObjectType, "GCMarkMembers"); BF_ASSERT(markMethod != NULL); diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index c2407a3e..d51544c7 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -4297,7 +4297,7 @@ BfTypedValue BfModule::GetFieldInitializerValue(BfFieldInstance* fieldInstance, int ceExecuteId = -1; if (mCompiler->mCEMachine != NULL) ceExecuteId = mCompiler->mCEMachine->mExecuteId; - + BfTypeState typeState; typeState.mType = mCurTypeInstance; typeState.mCurTypeDef = fieldDef->mDeclaringType; diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 70fa7133..73b8459f 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -1189,7 +1189,10 @@ void BfModule::PopulateType(BfType* resolvedTypeRef, BfPopulateType populateType } } - BfLogSysM("PopulateType: %p %s populateType:%d ResolveOnly:%d Reified:%d AutoComplete:%d Ctx:%p Mod:%p TypeId:%d\n", resolvedTypeRef, TypeToString(resolvedTypeRef, BfTypeNameFlags_None).c_str(), populateType, mCompiler->mIsResolveOnly, mIsReified, mCompiler->IsAutocomplete(), mContext, this, resolvedTypeRef->mTypeId); + BfTypeDef* typeDef = NULL; + if (typeInstance != NULL) + typeDef = typeInstance->mTypeDef; + BfLogSysM("PopulateType: %p %s populateType:%d ResolveOnly:%d Reified:%d AutoComplete:%d Ctx:%p Mod:%p TypeId:%d TypeDef:%p\n", resolvedTypeRef, TypeToString(resolvedTypeRef, BfTypeNameFlags_None).c_str(), populateType, mCompiler->mIsResolveOnly, mIsReified, mCompiler->IsAutocomplete(), mContext, this, resolvedTypeRef->mTypeId, typeDef); BF_ASSERT(!resolvedTypeRef->IsDeleting()); } @@ -2078,7 +2081,7 @@ void BfModule::UpdateCEEmit(CeEmitContext* ceEmitContext, BfTypeInstance* typeIn { for (int ifaceTypeId : ceEmitContext->mInterfaces) typeInstance->mCeTypeInfo->mPendingInterfaces.Add(ifaceTypeId); - + if (ceEmitContext->mEmitData.IsEmpty()) return; @@ -2166,12 +2169,7 @@ void BfModule::HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance* if (!attrType->IsValuelessType()) args.Add(attrVal); args.Add(mBfIRBuilder->CreateTypeOf(typeInstance)); - - //TESTING -// mCompiler->mCEMachine->ReleaseContext(ceContext); -// ceContext = mCompiler->mCEMachine->AllocContext(); -// ceContext->mMemory.mSize = ceContext->mMemory.mAllocSize; - + auto result = ceContext->Call(customAttribute.mRef, this, methodInstance, args, CeEvalFlags_None, NULL); if (typeInstance->mDefineState == BfTypeDefineState_DefinedAndMethodsSlotted) @@ -2182,7 +2180,7 @@ void BfModule::HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance* // We populated before we could finish AssertErrorState(); } - else + else { auto owner = methodInstance->GetOwner(); int typeId = owner->mTypeId; @@ -3732,6 +3730,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy if (typeInstance->mTypeDef != innerTypeInst->mTypeDef) { // Rebuild with proper typedef (generally from inner type comptime emission) + BfLogSysM("Boxed type %p overriding typeDef to %p from inner type %p\n", typeInstance, innerTypeInst->mTypeDef, innerType); typeInstance->mTypeDef = innerTypeInst->mTypeDef; DoPopulateType(resolvedTypeRef, populateType); return; diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index 9b9a1321..f02f097c 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -1823,23 +1823,7 @@ public: String mEmitData; }; -class BfCeTypeInfo -{ -public: - Dictionary mOnCompileMap; - Dictionary mTypeIFaceMap; - Array mPendingInterfaces; - Val128 mHash; - bool mFailed; - BfCeTypeInfo* mNext; - -public: - BfCeTypeInfo() - { - mFailed = false; - mNext = NULL; - } -}; +class BfCeTypeInfo; // Instance of struct or class class BfTypeInstance : public BfDependedType diff --git a/IDEHelper/Compiler/BfSystem.cpp b/IDEHelper/Compiler/BfSystem.cpp index de407542..236f5406 100644 --- a/IDEHelper/Compiler/BfSystem.cpp +++ b/IDEHelper/Compiler/BfSystem.cpp @@ -4159,11 +4159,12 @@ BF_EXPORT const char* BF_CALLTYPE BfSystem_GetNamespaceSearch(BfSystem* bfSystem return outString.c_str(); } -BF_EXPORT BfProject* BF_CALLTYPE BfSystem_CreateProject(BfSystem* bfSystem, const char* projectName) +BF_EXPORT BfProject* BF_CALLTYPE BfSystem_CreateProject(BfSystem* bfSystem, const char* projectName, const char* projectDir) { AutoCrit autoCrit(bfSystem->mDataLock); BfProject* bfProject = new BfProject(); bfProject->mName = projectName; + bfProject->mDirectory = projectDir; bfProject->mSystem = bfSystem; bfProject->mIdx = (int)bfSystem->mProjects.size(); bfSystem->mProjects.push_back(bfProject); diff --git a/IDEHelper/Compiler/BfSystem.h b/IDEHelper/Compiler/BfSystem.h index 1a4fbd93..4a0184c9 100644 --- a/IDEHelper/Compiler/BfSystem.h +++ b/IDEHelper/Compiler/BfSystem.h @@ -1180,6 +1180,7 @@ public: BfSystem* mSystem; String mName; String mSafeName; + String mDirectory; Array mDependencies; BfTargetType mTargetType; BfCodeGenOptions mCodeGenOptions; diff --git a/IDEHelper/Compiler/CeMachine.cpp b/IDEHelper/Compiler/CeMachine.cpp index b8054687..d29d2d40 100644 --- a/IDEHelper/Compiler/CeMachine.cpp +++ b/IDEHelper/Compiler/CeMachine.cpp @@ -6,6 +6,8 @@ #include "BfReducer.h" #include "BfExprEvaluator.h" #include "../Backend/BeIRCodeGen.h" +#include "BeefySysLib/platform/PlatformHelper.h" + extern "C" { #include "BeefySysLib/third_party/utf8proc/utf8proc.h" @@ -301,6 +303,24 @@ static int DoubleToString(double d, char* outStr) ////////////////////////////////////////////////////////////////////////// +CeInternalData::~CeInternalData() +{ + switch (mKind) + { + case Kind_File: + BfpFile_Release(mFile); + break; + case Kind_FindFileData: + BfpFindFileData_Release(mFindFileData); + break; + case Kind_Spawn: + BfpSpawn_Release(mSpawn); + break; + } +} + +////////////////////////////////////////////////////////////////////////// + CeFunction::~CeFunction() { BF_ASSERT(mId == -1); @@ -1316,6 +1336,11 @@ void CeBuilder::Build() if (mCeFunction->mInitializeState == CeFunction::InitializeState_Initialized) return; + if (methodInstance->mMethodDef->mName == "DecodeToUTF8") + { + NOP; + } + if (!dupMethodInstance.mIRFunction) { mCeFunction->mFailed = true; @@ -2886,6 +2911,7 @@ CeContext::CeContext() CeContext::~CeContext() { delete mHeap; + BF_ASSERT(mInternalDataMap.IsEmpty()); } BfError* CeContext::Fail(const StringImpl& error) @@ -2996,6 +3022,17 @@ BfError* CeContext::Fail(const CeFrame& curFrame, const StringImpl& str) ////////////////////////////////////////////////////////////////////////// +void CeContext::AddRebuild(const CeRebuildKey& key, const CeRebuildValue& value) +{ + if (mCurModule == NULL) + return; + if (mCurModule->mCurTypeInstance == NULL) + return; + if (mCurModule->mCurTypeInstance->mCeTypeInfo == NULL) + mCurModule->mCurTypeInstance->mCeTypeInfo = new BfCeTypeInfo(); + mCurModule->mCurTypeInstance->mCeTypeInfo->mRebuildMap[key] = value; +} + uint8* CeContext::CeMalloc(int size) { #ifdef CE_ENABLE_HEAP @@ -4308,6 +4345,59 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns return false; \ } +#define CE_CHECKADDR_STR(STRNAME, ADDR) \ + { \ + addr_ce checkAddr = ADDR; \ + while (true) \ + { \ + if ((uintptr)checkAddr >= (uintptr)memSize) \ + { \ + break; \ + } \ + if (memStart[checkAddr] == 0) \ + { \ + CE_CHECKADDR(ADDR, checkAddr - ADDR + 1); \ + STRNAME = String::MakeRef((char*)memStart + ADDR, checkAddr - ADDR + 1); \ + break; \ + } \ + checkAddr++; \ + } \ + } + +#define CE_GET_INTERNAL(VAR, ID, KIND) \ + if (!mInternalDataMap.TryGetValue((int)ID, &VAR)) \ + { \ + _Fail("Invalid internal resource id"); \ + return false; \ + } \ + if (VAR->mKind != KIND) \ + { \ + _Fail("Invalid internal resource kind"); \ + return false; \ + } \ + if (VAR->mReleased) \ + { \ + _Fail("Resource already released"); \ + return false; \ + } + +#define CE_REMOVE_INTERNAL(VAR, ID, KIND) \ + if (!mInternalDataMap.Remove((int)ID, &VAR)) \ + { \ + _Fail("Invalid internal resource id"); \ + return false; \ + } \ + if (VAR->mKind != KIND) \ + { \ + _Fail("Invalid internal resource kind"); \ + return false; \ + } \ + if (VAR->mReleased) \ + { \ + _Fail("Resource already released"); \ + return false; \ + } + #define CE_GETINST(T) *((T*)(instPtr += sizeof(T)) - 1) #define CE_GETFRAME(T) *(T*)(framePtr + *((int32*)(instPtr += sizeof(int32)) - 1)) #define CEOP_BIN(OP, T) \ @@ -4422,7 +4512,7 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns instPtr = &ceFunction->mCode[0]; \ CE_CHECKSTACK(); -static void CeSetAddrVal(void* ptr, addr_ce val, int32 ptrSize) +static void CeSetAddrVal(void* ptr, int64 val, int32 ptrSize) { if (ptrSize == 4) *(int32*)(ptr) = (int32)val; @@ -4559,8 +4649,16 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* } else if (checkFunction->mFunctionKind == CeFunctionKind_DebugWrite_Int) { - int32 intVal = *(int32*)((uint8*)stackPtr + 0); - OutputDebugStrF("Debug Val: %d\n", intVal); + if (ceModule->mSystem->mPtrSize == 4) + { + int32 intVal = *(int32*)((uint8*)stackPtr + 0); + OutputDebugStrF("Debug Val: %d\n", intVal); + } + else + { + int64 intVal = *(int64*)((uint8*)stackPtr + 0); + OutputDebugStrF("Debug Val: %lld\n", intVal); + } } else if (checkFunction->mFunctionKind == CeFunctionKind_GetReflectType) { @@ -4911,7 +5009,7 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* addr_ce strAddr = *(addr_ce*)((uint8*)stackPtr + 8); addr_ce endAddr = *(addr_ce*)((uint8*)stackPtr + 8 + ptrSize); - addr_ce checkAddr = strAddr; + addr_ce checkAddr = strAddr; while (true) { if ((uintptr)checkAddr >= (uintptr)memSize) @@ -4921,10 +5019,11 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* } if (memStart[checkAddr] == 0) break; + checkAddr++; } CE_CHECKADDR(strAddr, checkAddr - strAddr + 1); - char* strPtr = (char*)(memStart + strAddr); + char* strPtr = (char*)(memStart + strAddr); char** endPtr = NULL; if (endAddr != NULL) endPtr = (char**)(memStart + endAddr); @@ -4959,7 +5058,281 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* memcpy(memStart + strAddr, str, count + 1); result = count; } - else + else if (checkFunction->mFunctionKind == CeFunctionKind_BfpFile_Close) + { + addr_ce fileId = *(addr_ce*)((uint8*)stackPtr + 0); + addr_ce outResultAddr = *(addr_ce*)((uint8*)stackPtr + ptrSize); + + CE_CHECKADDR(outResultAddr, 4); + + CeInternalData* internalData = NULL; + CE_GET_INTERNAL(internalData, (int)fileId, CeInternalData::Kind_File); + BfpFile_Close(internalData->mFile, (BfpFileResult*)(memStart + outResultAddr)); + } + else if (checkFunction->mFunctionKind == CeFunctionKind_BfpFile_Create) + { + void* resultPtr = ((uint8*)stackPtr + 0); + addr_ce nameAddr = *(addr_ce*)((uint8*)stackPtr + ptrSize); + int createKind = *(int*)((uint8*)stackPtr + ptrSize + ptrSize); + int createFlags = *(int*)((uint8*)stackPtr + ptrSize + ptrSize + 4); + int createFileAttrs = *(int*)((uint8*)stackPtr + ptrSize + ptrSize + 4 + 4); + addr_ce outResultAddr = *(addr_ce*)((uint8*)stackPtr + ptrSize + ptrSize + 4 + 4 + 4); + + String path; + CE_CHECKADDR_STR(path, nameAddr); + CE_CHECKADDR(outResultAddr, 4); + + BfProject* activeProject = NULL; + auto activeTypeDef = mCurModule->GetActiveTypeDef(); + if (activeTypeDef != NULL) + activeProject = activeTypeDef->mProject; + if (activeProject != NULL) + path = GetAbsPath(path, activeProject->mDirectory); + + auto bfpFile = BfpFile_Create(path.c_str(), (BfpFileCreateKind)createKind, (BfpFileCreateFlags)createFlags, (BfpFileAttributes)createFileAttrs, (BfpFileResult*)(memStart + outResultAddr)); + if (bfpFile != NULL) + { + if ((createKind == BfpFileCreateKind_OpenExisting) || (createKind == BfpFileCreateKind_OpenAlways)) + { + auto timeStamp = BfpFile_GetTime_LastWrite(path.c_str()); + if (timeStamp != 0) + { + CeRebuildKey rebuildKey; + rebuildKey.mKind = CeRebuildKey::Kind_File; + rebuildKey.mString = path; + + CeRebuildValue rebuildValue; + rebuildValue.mInt = timeStamp; + + AddRebuild(rebuildKey, rebuildValue); + } + } + + CeInternalData* internalData = new CeInternalData(); + internalData->mKind = CeInternalData::Kind_File; + internalData->mFile = bfpFile; + mInternalDataMap[++mCurHandleId] = internalData; + CeSetAddrVal(resultPtr, mCurHandleId, ptrSize); + } + else + CeSetAddrVal(resultPtr, 0, ptrSize); + } + else if (checkFunction->mFunctionKind == CeFunctionKind_BfpFile_Flush) + { + addr_ce fileId = *(addr_ce*)((uint8*)stackPtr + 0); + CeInternalData* internalData = NULL; + CE_GET_INTERNAL(internalData, (int)fileId, CeInternalData::Kind_File); + BfpFile_Flush(internalData->mFile); + } + else if (checkFunction->mFunctionKind == CeFunctionKind_BfpFile_GetFileSize) + { + int64& result = *(int64*)((uint8*)stackPtr + 0); + addr_ce fileId = *(addr_ce*)((uint8*)stackPtr + 8); + CeInternalData* internalData = NULL; + CE_GET_INTERNAL(internalData, (int)fileId, CeInternalData::Kind_File); + result = BfpFile_GetFileSize(internalData->mFile); + } + else if (checkFunction->mFunctionKind == CeFunctionKind_BfpFile_Read) + { + void* resultPtr = ((uint8*)stackPtr + 0); + addr_ce fileId = *(addr_ce*)((uint8*)stackPtr + ptrSize); + addr_ce bufferPtr = *(addr_ce*)((uint8*)stackPtr + ptrSize + ptrSize); + intptr bufferSize = *(addr_ce*)((uint8*)stackPtr + ptrSize + ptrSize + ptrSize); + int timeoutMS = *(int32*)((uint8*)stackPtr + ptrSize + ptrSize + ptrSize + ptrSize); + addr_ce outResultAddr = *(addr_ce*)((uint8*)stackPtr + ptrSize + ptrSize + ptrSize + ptrSize + ptrSize); + + CE_CHECKADDR(bufferPtr, bufferSize); + CE_CHECKADDR(outResultAddr, 4); + + CeInternalData* internalData = NULL; + CE_GET_INTERNAL(internalData, (int)fileId, CeInternalData::Kind_File); + int64 result = BfpFile_Read(internalData->mFile, memStart + bufferPtr, bufferSize, timeoutMS, (BfpFileResult*)(memStart + outResultAddr)); + CeSetAddrVal(resultPtr, result, ptrSize); + } + else if (checkFunction->mFunctionKind == CeFunctionKind_BfpFile_Release) + { + addr_ce fileId = *(addr_ce*)((uint8*)stackPtr + 0); + + CeInternalData* internalData = NULL; + CE_REMOVE_INTERNAL(internalData, (int)fileId, CeInternalData::Kind_File); + delete internalData; + } + else if (checkFunction->mFunctionKind == CeFunctionKind_BfpFile_Seek) + { + int64& result = *(int64*)((uint8*)stackPtr + 0); + addr_ce fileId = *(addr_ce*)((uint8*)stackPtr + 8); + int64 offset = *(int64*)((uint8*)stackPtr + 8 + ptrSize); + int seekKind = *(int*)((uint8*)stackPtr + 8 + ptrSize + 8); + CeInternalData* internalData = NULL; + CE_GET_INTERNAL(internalData, (int)fileId, CeInternalData::Kind_File); + result = BfpFile_Seek(internalData->mFile, offset, (BfpFileSeekKind)seekKind); + } + else if (checkFunction->mFunctionKind == CeFunctionKind_BfpFile_Truncate) + { + addr_ce fileId = *(addr_ce*)((uint8*)stackPtr + 0); + addr_ce outResultAddr = *(addr_ce*)((uint8*)stackPtr + ptrSize); + + CE_CHECKADDR(outResultAddr, 4); + + CeInternalData* internalData = NULL; + CE_GET_INTERNAL(internalData, (int)fileId, CeInternalData::Kind_File); + BfpFile_Truncate(internalData->mFile, (BfpFileResult*)(memStart + outResultAddr)); + } + else if (checkFunction->mFunctionKind == CeFunctionKind_BfpFile_Write) + { + void* resultPtr = ((uint8*)stackPtr + 0); + addr_ce fileId = *(addr_ce*)((uint8*)stackPtr + ptrSize); + addr_ce bufferPtr = *(addr_ce*)((uint8*)stackPtr + ptrSize + ptrSize); + intptr bufferSize = *(addr_ce*)((uint8*)stackPtr + ptrSize + ptrSize + ptrSize); + int timeoutMS = *(int32*)((uint8*)stackPtr + ptrSize + ptrSize + ptrSize + ptrSize); + addr_ce outResultAddr = *(addr_ce*)((uint8*)stackPtr + ptrSize + ptrSize + ptrSize + ptrSize + ptrSize); + + CE_CHECKADDR(bufferPtr, bufferSize); + CE_CHECKADDR(outResultAddr, 4); + + CeInternalData* internalData = NULL; + CE_GET_INTERNAL(internalData, (int)fileId, CeInternalData::Kind_File); + int64 result = BfpFile_Write(internalData->mFile, memStart + bufferPtr, bufferSize, timeoutMS, (BfpFileResult*)(memStart + outResultAddr)); + CeSetAddrVal(resultPtr, result, ptrSize); + } + else if (checkFunction->mFunctionKind == CeFunctionKind_BfpSpawn_Create) + { + void* resultPtr = ((uint8*)stackPtr + 0); + addr_ce targetPathAddr = *(addr_ce*)((uint8*)stackPtr + ptrSize); + addr_ce argsAddr = *(addr_ce*)((uint8*)stackPtr + ptrSize + ptrSize); + addr_ce workingDirAddr = *(addr_ce*)((uint8*)stackPtr + ptrSize + ptrSize + ptrSize); + addr_ce envAddr = *(addr_ce*)((uint8*)stackPtr + ptrSize + ptrSize + ptrSize + ptrSize); + int flags = *(int*)((uint8*)stackPtr + ptrSize + ptrSize + ptrSize + ptrSize + ptrSize); + addr_ce outResultAddr = *(addr_ce*)((uint8*)stackPtr + ptrSize + ptrSize + ptrSize + ptrSize + ptrSize + ptrSize); + + String targetPath; + CE_CHECKADDR_STR(targetPath, targetPathAddr); + String args; + CE_CHECKADDR_STR(args, argsAddr); + String workingDir; + CE_CHECKADDR_STR(workingDir, workingDirAddr); + String env; + CE_CHECKADDR_STR(env, envAddr); + CE_CHECKADDR(outResultAddr, 4); + + BfProject* activeProject = NULL; + auto activeTypeDef = mCurModule->GetActiveTypeDef(); + if (activeTypeDef != NULL) + activeProject = activeTypeDef->mProject; + if (activeProject != NULL) + targetPath = GetAbsPath(targetPath, activeProject->mDirectory); + + auto bfpSpawn = BfpSpawn_Create(targetPath.c_str(), args.c_str(), workingDir.c_str(), env.c_str(), (BfpSpawnFlags)flags, (BfpSpawnResult*)(memStart + outResultAddr)); + if (bfpSpawn != NULL) + { + CeInternalData* internalData = new CeInternalData(); + internalData->mKind = CeInternalData::Kind_Spawn; + internalData->mSpawn = bfpSpawn; + mInternalDataMap[++mCurHandleId] = internalData; + CeSetAddrVal(resultPtr, mCurHandleId, ptrSize); + } + else + CeSetAddrVal(resultPtr, 0, ptrSize); + } + else if (checkFunction->mFunctionKind == CeFunctionKind_BfpSpawn_GetStdHandles) + { + addr_ce spawnId = *(addr_ce*)((uint8*)stackPtr + 0); + addr_ce outStdInAddr = *(addr_ce*)((uint8*)stackPtr + ptrSize); + addr_ce outStdOutAddr = *(addr_ce*)((uint8*)stackPtr + ptrSize + ptrSize); + addr_ce outStdErrAddr = *(addr_ce*)((uint8*)stackPtr + ptrSize + ptrSize + ptrSize); + + CE_CHECKADDR(outStdInAddr, ptrSize); + CE_CHECKADDR(outStdOutAddr, ptrSize); + CE_CHECKADDR(outStdErrAddr, ptrSize); + + BfpFile* outStdIn = NULL; + BfpFile* outStdOut = NULL; + BfpFile* outStdErr = NULL; + + CeInternalData* internalData = NULL; + CE_GET_INTERNAL(internalData, (int)spawnId, CeInternalData::Kind_Spawn); + BfpSpawn_GetStdHandles(internalData->mSpawn, + (outStdInAddr != 0) ? &outStdIn : NULL, + (outStdOutAddr != 0) ? &outStdOut : NULL, + (outStdErrAddr != 0) ? &outStdErr : NULL); + + auto _SetHandle = [&](addr_ce addr, BfpFile* file) + { + if (addr == 0) + return; + if (file != NULL) + { + CeInternalData* internalData = new CeInternalData(); + internalData->mKind = CeInternalData::Kind_File; + internalData->mFile = file; + mInternalDataMap[++mCurHandleId] = internalData; + CeSetAddrVal(memStart + addr, mCurHandleId, ptrSize); + } + }; + + _SetHandle(outStdInAddr, outStdIn); + _SetHandle(outStdOutAddr, outStdOut); + _SetHandle(outStdErrAddr, outStdErr); + } + else if (checkFunction->mFunctionKind == CeFunctionKind_BfpSpawn_Kill) + { + addr_ce spawnId = *(addr_ce*)((uint8*)stackPtr + 0); + int exitCode = *(int*)((uint8*)stackPtr + ptrSize); + int killFlags = *(int*)((uint8*)stackPtr + ptrSize + ptrSize); + addr_ce outResultAddr = *(addr_ce*)((uint8*)stackPtr + ptrSize + ptrSize + ptrSize); + + CE_CHECKADDR(outResultAddr, 4); + + CeInternalData* internalData = NULL; + CE_GET_INTERNAL(internalData, (int)spawnId, CeInternalData::Kind_Spawn); + BfpSpawn_Kill(internalData->mSpawn, exitCode, (BfpKillFlags)killFlags, (BfpSpawnResult*)(memStart + outResultAddr)); + } + else if (checkFunction->mFunctionKind == CeFunctionKind_BfpSpawn_Release) + { + addr_ce spawnId = *(addr_ce*)((uint8*)stackPtr + 0); + CeInternalData* internalData = NULL; + CE_GET_INTERNAL(internalData, (int)spawnId, CeInternalData::Kind_Spawn); + internalData->mReleased = true; + } + else if (checkFunction->mFunctionKind == CeFunctionKind_BfpSpawn_WaitFor) + { + bool& result = *(bool*)((uint8*)stackPtr + 0); + addr_ce spawnId = *(addr_ce*)((uint8*)stackPtr + 1); + int waitMS = *(int*)((uint8*)stackPtr + 1 + ptrSize); + addr_ce outExitCodeAddr = *(addr_ce*)((uint8*)stackPtr + 1 + ptrSize + ptrSize); + addr_ce outResultAddr = *(addr_ce*)((uint8*)stackPtr + 1 + ptrSize + ptrSize + ptrSize); + + CE_CHECKADDR(outExitCodeAddr, ptrSize); + CE_CHECKADDR(outResultAddr, 4); + + CeInternalData* internalData = NULL; + CE_GET_INTERNAL(internalData, (int)spawnId, CeInternalData::Kind_Spawn); + + int timeLeft = waitMS; + do + { + if (*fastFinishPtr) + { + result = false; + break; + } + + int waitTime = 20; + if (timeLeft >= 0) + { + waitTime = BF_MIN(timeLeft, 20); + timeLeft -= waitTime; + } + + int outExitCode = 0; + result = BfpSpawn_WaitFor(internalData->mSpawn, waitTime, &outExitCode, (BfpSpawnResult*)(memStart + outResultAddr)); + if (result) + break; + if (waitTime == 0) + break; + } while (true); + } + else { Fail(_GetCurFrame(), StrFormat("Unable to invoke extern method '%s'", ceModule->MethodToString(checkFunction->mMethodInstance).c_str())); return false; @@ -5005,6 +5378,17 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* ++instIdx; + if (instIdx >= /*0xBC0*/0xBA0) + { + NOP; + } + +// if (instIdx == 0x444) +// { +// _CrtCheckMemory(); +// NOP; +// } + CeOp op = CE_GETINST(CeOp); switch (op) { @@ -5580,7 +5964,12 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* auto valueType = bfType->ToTypeInstance(); if (valueType->mVirtualMethodTable.IsEmpty()) - ceModule->PopulateType(valueType, BfPopulateType_DataAndMethods); + ceModule->PopulateType(valueType, BfPopulateType_Full_Force); + if (valueType->mVirtualMethodTable.IsEmpty()) + { + _Fail("Empty virtual table"); + return false; + } auto methodInstance = (BfMethodInstance*)valueType->mVirtualMethodTable[virtualIdx].mImplementingMethod; auto callFunction = mCeMachine->GetPreparedFunction(methodInstance); @@ -6338,6 +6727,8 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* _Fail("Unhandled op"); return false; } + + //BF_ASSERT(_CrtCheckMemory() != 0); } return true; @@ -6359,7 +6750,7 @@ CeMachine::CeMachine(BfCompiler* compiler) mCurBuilder = NULL; mPreparingFunction = NULL; - mCurEmitContext = NULL; + mCurEmitContext = NULL; mAppendAllocInfo = NULL; mTempParser = NULL; @@ -6893,6 +7284,34 @@ void CeMachine::CheckFunctionKind(CeFunction* ceFunction) { if (methodDef->mName == "BfpSystem_GetTimeStamp") ceFunction->mFunctionKind = CeFunctionKind_BfpSystem_GetTimeStamp; + else if (methodDef->mName == "BfpFile_Close") + ceFunction->mFunctionKind = CeFunctionKind_BfpFile_Close; + else if (methodDef->mName == "BfpFile_Create") + ceFunction->mFunctionKind = CeFunctionKind_BfpFile_Create; + else if (methodDef->mName == "BfpFile_Flush") + ceFunction->mFunctionKind = CeFunctionKind_BfpFile_Flush; + else if (methodDef->mName == "BfpFile_GetFileSize") + ceFunction->mFunctionKind = CeFunctionKind_BfpFile_GetFileSize; + else if (methodDef->mName == "BfpFile_Read") + ceFunction->mFunctionKind = CeFunctionKind_BfpFile_Read; + else if (methodDef->mName == "BfpFile_Release") + ceFunction->mFunctionKind = CeFunctionKind_BfpFile_Release; + else if (methodDef->mName == "BfpFile_Seek") + ceFunction->mFunctionKind = CeFunctionKind_BfpFile_Seek; + else if (methodDef->mName == "BfpFile_Truncate") + ceFunction->mFunctionKind = CeFunctionKind_BfpFile_Truncate; + else if (methodDef->mName == "BfpFile_Write") + ceFunction->mFunctionKind = CeFunctionKind_BfpFile_Write; + else if (methodDef->mName == "BfpSpawn_Create") + ceFunction->mFunctionKind = CeFunctionKind_BfpSpawn_Create; + else if (methodDef->mName == "BfpSpawn_GetStdHandles") + ceFunction->mFunctionKind = CeFunctionKind_BfpSpawn_GetStdHandles; + else if (methodDef->mName == "BfpSpawn_Kill") + ceFunction->mFunctionKind = CeFunctionKind_BfpSpawn_Kill; + else if (methodDef->mName == "BfpSpawn_Release") + ceFunction->mFunctionKind = CeFunctionKind_BfpSpawn_Release; + else if (methodDef->mName == "BfpSpawn_WaitFor") + ceFunction->mFunctionKind = CeFunctionKind_BfpSpawn_WaitFor; } else if (owner->IsInstanceOf(mCeModule->mCompiler->mChar32TypeDef)) { @@ -6926,45 +7345,45 @@ void CeMachine::CheckFunctionKind(CeFunction* ceFunction) { if (methodDef->mName == "Abs") ceFunction->mFunctionKind = CeFunctionKind_Math_Abs; - if (methodDef->mName == "Acos") + else if (methodDef->mName == "Acos") ceFunction->mFunctionKind = CeFunctionKind_Math_Acos; - if (methodDef->mName == "Asin") + else if (methodDef->mName == "Asin") ceFunction->mFunctionKind = CeFunctionKind_Math_Asin; - if (methodDef->mName == "Atan") + else if (methodDef->mName == "Atan") ceFunction->mFunctionKind = CeFunctionKind_Math_Atan; - if (methodDef->mName == "Atan2") + else if (methodDef->mName == "Atan2") ceFunction->mFunctionKind = CeFunctionKind_Math_Atan2; - if (methodDef->mName == "Ceiling") + else if (methodDef->mName == "Ceiling") ceFunction->mFunctionKind = CeFunctionKind_Math_Ceiling; - if (methodDef->mName == "Cos") + else if (methodDef->mName == "Cos") ceFunction->mFunctionKind = CeFunctionKind_Math_Cos; - if (methodDef->mName == "Cosh") + else if (methodDef->mName == "Cosh") ceFunction->mFunctionKind = CeFunctionKind_Math_Cosh; - if (methodDef->mName == "Exp") + else if (methodDef->mName == "Exp") ceFunction->mFunctionKind = CeFunctionKind_Math_Exp; - if (methodDef->mName == "Floor") + else if (methodDef->mName == "Floor") ceFunction->mFunctionKind = CeFunctionKind_Math_Floor; - if (methodDef->mName == "Log") + else if (methodDef->mName == "Log") ceFunction->mFunctionKind = CeFunctionKind_Math_Log; - if (methodDef->mName == "Log10") + else if (methodDef->mName == "Log10") ceFunction->mFunctionKind = CeFunctionKind_Math_Log10; - if (methodDef->mName == "Mod") + else if (methodDef->mName == "Mod") ceFunction->mFunctionKind = CeFunctionKind_Math_Mod; - if (methodDef->mName == "Pow") + else if (methodDef->mName == "Pow") ceFunction->mFunctionKind = CeFunctionKind_Math_Pow; - if (methodDef->mName == "Round") + else if (methodDef->mName == "Round") ceFunction->mFunctionKind = CeFunctionKind_Math_Round; - if (methodDef->mName == "Sin") + else if (methodDef->mName == "Sin") ceFunction->mFunctionKind = CeFunctionKind_Math_Sin; - if (methodDef->mName == "Sinh") + else if (methodDef->mName == "Sinh") ceFunction->mFunctionKind = CeFunctionKind_Math_Sinh; - if (methodDef->mName == "Sqrt") + else if (methodDef->mName == "Sqrt") ceFunction->mFunctionKind = CeFunctionKind_Math_Sqrt; - if (methodDef->mName == "Tan") + else if (methodDef->mName == "Tan") ceFunction->mFunctionKind = CeFunctionKind_Math_Tan; - if (methodDef->mName == "Tanh") + else if (methodDef->mName == "Tanh") ceFunction->mFunctionKind = CeFunctionKind_Math_Tanh; - } + } ceFunction->mInitializeState = CeFunction::InitializeState_Initialized; return; @@ -7214,11 +7633,12 @@ CeContext* CeMachine::AllocContext() ceContext->mMemory.Reserve(BF_CE_INITIAL_MEMORY); } - ceContext->mCurEmitContext = mCurEmitContext; - mCurEmitContext = NULL; + ceContext->mCurEmitContext = mCurEmitContext; + mCurEmitContext = NULL; mExecuteId++; ceContext->mMemory.Resize(BF_CE_STACK_SIZE); ceContext->mExecuteId = mExecuteId; + ceContext->mCurHandleId = 0; return ceContext; } @@ -7234,9 +7654,12 @@ void CeMachine::ReleaseContext(CeContext* ceContext) ceContext->mStaticFieldMap.Clear(); ceContext->mHeap->Clear(BF_CE_MAX_CARRYOVER_HEAP); ceContext->mReflectTypeIdOffset = -1; - mCurEmitContext = ceContext->mCurEmitContext; - ceContext->mCurEmitContext = NULL; + mCurEmitContext = ceContext->mCurEmitContext; + ceContext->mCurEmitContext = NULL; mContextList.Add(ceContext); + for (auto kv : ceContext->mInternalDataMap) + delete kv.mValue; + ceContext->mInternalDataMap.Clear(); } BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodInstance* methodInstance, const BfSizedArray& args, CeEvalFlags flags, BfType* expectingType) @@ -7246,3 +7669,5 @@ BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns ReleaseContext(ceContext); return result; } + + diff --git a/IDEHelper/Compiler/CeMachine.h b/IDEHelper/Compiler/CeMachine.h index ca36f4b0..c8eef486 100644 --- a/IDEHelper/Compiler/CeMachine.h +++ b/IDEHelper/Compiler/CeMachine.h @@ -264,6 +264,37 @@ public: } }; +class CeInternalData +{ +public: + enum Kind + { + Kind_None, + Kind_File, + Kind_FindFileData, + Kind_Spawn + }; + +public: + Kind mKind; + bool mReleased; + + union + { + BfpFile* mFile; + BfpFindFileData* mFindFileData; + BfpSpawn* mSpawn; + }; + + CeInternalData() + { + mKind = Kind_None; + mReleased = false; + } + + ~CeInternalData(); +}; + enum CeFunctionKind { CeFunctionKind_NotSet, @@ -294,6 +325,21 @@ enum CeFunctionKind CeFunctionKind_EmitMethodExit, CeFunctionKind_EmitMixin, + CeFunctionKind_BfpFile_Close, + CeFunctionKind_BfpFile_Create, + CeFunctionKind_BfpFile_Flush, + CeFunctionKind_BfpFile_GetFileSize, + CeFunctionKind_BfpFile_Read, + CeFunctionKind_BfpFile_Release, + CeFunctionKind_BfpFile_Seek, + CeFunctionKind_BfpFile_Truncate, + CeFunctionKind_BfpFile_Write, + CeFunctionKind_BfpSpawn_Create, + CeFunctionKind_BfpSpawn_GetStdHandles, + CeFunctionKind_BfpSpawn_Kill, + CeFunctionKind_BfpSpawn_Release, + CeFunctionKind_BfpSpawn_WaitFor, + CeFunctionKind_BfpSystem_GetTimeStamp, CeFunctionKind_Sleep, @@ -328,7 +374,7 @@ enum CeFunctionKind CeFunctionKind_Math_Sinh, CeFunctionKind_Math_Sqrt, CeFunctionKind_Math_Tan, - CeFunctionKind_Math_Tanh, + CeFunctionKind_Math_Tanh, }; class CeConstStructFixup @@ -683,12 +729,40 @@ public: BfIRValue mAppendSizeValue; }; +class CeRebuildKey +{ +public: + enum Kind + { + Kind_None, + Kind_File + }; + +public: + Kind mKind; + String mString; + + bool operator==(const CeRebuildKey& other) const + { + return (mKind == other.mKind) && (mString == other.mString); + } +}; + +class CeRebuildValue +{ +public: + union + { + uint64 mInt; + }; +}; + class CeEmitContext { public: - BfType* mType; + BfType* mType; BfMethodInstance* mMethodInstance; - Array mInterfaces; + Array mInterfaces; String mEmitData; String mExitEmitData; bool mFailed; @@ -706,6 +780,25 @@ public: } }; +class BfCeTypeInfo +{ +public: + Dictionary mOnCompileMap; + Dictionary mTypeIFaceMap; + Array mPendingInterfaces; + Dictionary mRebuildMap; + Val128 mHash; + bool mFailed; + BfCeTypeInfo* mNext; + +public: + BfCeTypeInfo() + { + mFailed = false; + mNext = NULL; + } +}; + class CeContext { public: @@ -724,14 +817,15 @@ public: Dictionary mConstDataMap; HashSet mStaticCtorExecSet; Dictionary mStaticFieldMap; - Dictionary mMemToCtxMap; + Dictionary mInternalDataMap; + int mCurHandleId; BfMethodInstance* mCurMethodInstance; BfType* mCurExpectingType; BfAstNode* mCurTargetSrc; BfModule* mCurModule; CeFrame* mCurFrame; - CeEmitContext* mCurEmitContext; + CeEmitContext* mCurEmitContext; public: CeContext(); @@ -740,6 +834,7 @@ public: BfError* Fail(const StringImpl& error); BfError* Fail(const CeFrame& curFrame, const StringImpl& error); + void AddRebuild(const CeRebuildKey& key, const CeRebuildValue& value); uint8* CeMalloc(int size); bool CeFree(addr_ce addr); addr_ce CeAllocArray(BfArrayType* arrayType, int count, addr_ce& elemsAddr); @@ -791,7 +886,7 @@ public: CeAppendAllocInfo* mAppendAllocInfo; CeContext* mCurContext; - CeEmitContext* mCurEmitContext; + CeEmitContext* mCurEmitContext; CeBuilder* mCurBuilder; CeFunction* mPreparingFunction; @@ -838,3 +933,15 @@ public: }; NS_BF_END + +namespace std +{ + template <> + struct hash + { + size_t operator()(const Beefy::CeRebuildKey& key) const + { + return BeefHash()(key.mString) ^ (size_t)key.mKind; + } + }; +} \ No newline at end of file diff --git a/IDEHelper/Tests/Test0.txt b/IDEHelper/Tests/Test0.txt new file mode 100644 index 00000000..5f0767fa --- /dev/null +++ b/IDEHelper/Tests/Test0.txt @@ -0,0 +1,2 @@ +Test +0 \ No newline at end of file diff --git a/IDEHelper/Tests/src/Comptime.bf b/IDEHelper/Tests/src/Comptime.bf index 453e39c7..326d9e57 100644 --- a/IDEHelper/Tests/src/Comptime.bf +++ b/IDEHelper/Tests/src/Comptime.bf @@ -229,6 +229,9 @@ namespace Tests GC.Mark!((*ptr)); } } + + const String cTest0 = Compiler.ReadText("Test0.txt"); + [Test] public static void TestBasics() { @@ -269,6 +272,8 @@ namespace Tests SerializationContext serCtx = scope .(); iSer.Serialize(serCtx); Test.Assert(serCtx.mStr == "x 10\ny 2\n"); + + Test.Assert(cTest0 == "Test\n0"); } } } From 4f83b61a106aa62b9bee738a1c3daa9ecfaa1f20 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 20 Dec 2021 09:52:29 -0500 Subject: [PATCH 068/139] Comptime rebuild flag --- IDE/src/Compiler/BfCompiler.bf | 8 ++++++++ IDE/src/IDEApp.bf | 6 +----- IDEHelper/Compiler/BfCompiler.cpp | 13 +++++++++++++ IDEHelper/Compiler/BfCompiler.h | 4 +++- IDEHelper/Compiler/BfContext.cpp | 1 + IDEHelper/Compiler/CeMachine.cpp | 1 + IDEHelper/Tests/src/Comptime.bf | 4 +++- 7 files changed, 30 insertions(+), 7 deletions(-) diff --git a/IDE/src/Compiler/BfCompiler.bf b/IDE/src/Compiler/BfCompiler.bf index efc60b19..4933ef06 100644 --- a/IDE/src/Compiler/BfCompiler.bf +++ b/IDE/src/Compiler/BfCompiler.bf @@ -76,6 +76,9 @@ namespace IDE.Compiler [CallingConvention(.Stdcall), CLink] static extern int32 BfCompiler_GetCurConstEvalExecuteId(void* bfCompiler); + [CallingConvention(.Stdcall), CLink] + static extern bool BfCompiler_GetLastHadComptimeRebuilds(void* bfCompiler); + [CallingConvention(.Stdcall), CLink] static extern void BfCompiler_Delete(void* bfCompiler); @@ -834,5 +837,10 @@ namespace IDE.Compiler } } } + + public bool GetLastHadComptimeRebuilds() + { + return BfCompiler_GetLastHadComptimeRebuilds(mNativeBfCompiler); + } } } diff --git a/IDE/src/IDEApp.bf b/IDE/src/IDEApp.bf index 14271dd5..103c65fd 100644 --- a/IDE/src/IDEApp.bf +++ b/IDE/src/IDEApp.bf @@ -9168,11 +9168,7 @@ namespace IDE if (lastCompileHadMessages) doCompile = true; - bool needsComptime = true; - for (var project in mWorkspace.mProjects) - { - //Set needsComptime - } + bool needsComptime = bfCompiler.GetLastHadComptimeRebuilds(); if ((!workspaceOptions.mIncrementalBuild) && (!lastCompileHadMessages)) { diff --git a/IDEHelper/Compiler/BfCompiler.cpp b/IDEHelper/Compiler/BfCompiler.cpp index f05743fa..9e2138b0 100644 --- a/IDEHelper/Compiler/BfCompiler.cpp +++ b/IDEHelper/Compiler/BfCompiler.cpp @@ -360,6 +360,8 @@ BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly) //mMaxInterfaceSlots = 16; mMaxInterfaceSlots = -1; mInterfaceSlotCountChanged = false; + mLastHadComptimeRebuilds = false; + mHasComptimeRebuilds = false; mHSPreserveIdx = 0; mCompileLogFP = NULL; @@ -6561,6 +6563,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory) // Inc revision for next run through Compile mRevision++; + mHasComptimeRebuilds = false; int revision = mRevision; BfLogSysM("Compile Start. Revision: %d. HasParser:%d AutoComplete:%d\n", revision, (mResolvePassData != NULL) && (mResolvePassData->mParser != NULL), @@ -7494,6 +7497,11 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory) return false; } + if (didCancel) + mLastHadComptimeRebuilds = mHasComptimeRebuilds || mLastHadComptimeRebuilds; + else + mLastHadComptimeRebuilds = mHasComptimeRebuilds; + return !didCancel && !mHasQueuedTypeRebuilds; } @@ -9081,6 +9089,11 @@ BF_EXPORT int BF_CALLTYPE BfCompiler_GetCurConstEvalExecuteId(BfCompiler* bfComp return bfCompiler->mCEMachine->mExecuteId; } +BF_EXPORT float BF_CALLTYPE BfCompiler_GetLastHadComptimeRebuilds(BfCompiler* bfCompiler) +{ + return bfCompiler->mLastHadComptimeRebuilds; +} + BF_EXPORT void BF_CALLTYPE BfCompiler_Cancel(BfCompiler* bfCompiler) { bfCompiler->Cancel(); diff --git a/IDEHelper/Compiler/BfCompiler.h b/IDEHelper/Compiler/BfCompiler.h index 9c2dbef6..4c79b85c 100644 --- a/IDEHelper/Compiler/BfCompiler.h +++ b/IDEHelper/Compiler/BfCompiler.h @@ -328,7 +328,9 @@ public: bool mFastFinish; bool mHasQueuedTypeRebuilds; // Infers we had a fast finish that requires a type rebuild bool mHadCancel; - bool mWantsDeferMethodDecls; + bool mWantsDeferMethodDecls; + bool mLastHadComptimeRebuilds; + bool mHasComptimeRebuilds; bool mInInvalidState; float mCompletionPct; int mHSPreserveIdx; diff --git a/IDEHelper/Compiler/BfContext.cpp b/IDEHelper/Compiler/BfContext.cpp index 81bd8c6a..477fd2ce 100644 --- a/IDEHelper/Compiler/BfContext.cpp +++ b/IDEHelper/Compiler/BfContext.cpp @@ -1947,6 +1947,7 @@ void BfContext::UpdateRevisedTypes() for (auto& kv : typeInst->mCeTypeInfo->mRebuildMap) { + mCompiler->mHasComptimeRebuilds = true; if (kv.mKey.mKind == CeRebuildKey::Kind_File) { String* keyPtr = NULL; diff --git a/IDEHelper/Compiler/CeMachine.cpp b/IDEHelper/Compiler/CeMachine.cpp index d29d2d40..33de381b 100644 --- a/IDEHelper/Compiler/CeMachine.cpp +++ b/IDEHelper/Compiler/CeMachine.cpp @@ -3031,6 +3031,7 @@ void CeContext::AddRebuild(const CeRebuildKey& key, const CeRebuildValue& value) if (mCurModule->mCurTypeInstance->mCeTypeInfo == NULL) mCurModule->mCurTypeInstance->mCeTypeInfo = new BfCeTypeInfo(); mCurModule->mCurTypeInstance->mCeTypeInfo->mRebuildMap[key] = value; + mCurModule->mCompiler->mHasComptimeRebuilds = true; } uint8* CeContext::CeMalloc(int size) diff --git a/IDEHelper/Tests/src/Comptime.bf b/IDEHelper/Tests/src/Comptime.bf index 326d9e57..55bfb785 100644 --- a/IDEHelper/Tests/src/Comptime.bf +++ b/IDEHelper/Tests/src/Comptime.bf @@ -231,7 +231,8 @@ namespace Tests } const String cTest0 = Compiler.ReadText("Test0.txt"); - + const uint8[?] cTest0Binary = Compiler.ReadBinary("Test0.txt"); + [Test] public static void TestBasics() { @@ -274,6 +275,7 @@ namespace Tests Test.Assert(serCtx.mStr == "x 10\ny 2\n"); Test.Assert(cTest0 == "Test\n0"); + Test.Assert((cTest0Binary[0] == (.)'T') && ((cTest0Binary.Count == 6) || (cTest0Binary.Count == 7))); } } } From 002fd075d1b2eeb83154d7ff0811ffea4bd27400 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 20 Dec 2021 09:57:44 -0500 Subject: [PATCH 069/139] BeefBoot fix --- BeefBoot/BootApp.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/BeefBoot/BootApp.cpp b/BeefBoot/BootApp.cpp index c7e420de..9f60e9b7 100644 --- a/BeefBoot/BootApp.cpp +++ b/BeefBoot/BootApp.cpp @@ -47,7 +47,7 @@ BF_IMPORT void BF_CALLTYPE BfSystem_ReportMemory(void* bfSystem); BF_IMPORT void BF_CALLTYPE BfSystem_Delete(void* bfSystem); BF_IMPORT void* BF_CALLTYPE BfSystem_CreatePassInstance(void* bfSystem); BF_IMPORT void* BF_CALLTYPE BfSystem_CreateCompiler(void* bfSystem, bool isResolveOnly); -BF_IMPORT void* BF_CALLTYPE BfSystem_CreateProject(void* bfSystem, const char* projectName); +BF_IMPORT void* BF_CALLTYPE BfSystem_CreateProject(void* bfSystem, const char* projectName, const char* projectDir); BF_IMPORT void BF_CALLTYPE BfParser_Delete(void* bfParser); BF_IMPORT void BF_CALLTYPE BfSystem_AddTypeOptions(void* bfSystem, const char* filter, int32 simdSetting, int32 optimizationLevel, int32 emitDebugInfo, int32 arrayBoundsCheck, int32 initLocalVariables, int32 emitDynamicCastCheck, int32 emitObjectAccessCheck, int32 allocStackTraceDepth); @@ -790,12 +790,12 @@ bool BootApp::Compile() projectName.RemoveToEnd(dotPos); if (projectName.IsEmpty()) projectName.Append("BeefProject"); - - mProject = BfSystem_CreateProject(mSystem, projectName.c_str()); + + mProject = BfSystem_CreateProject(mSystem, projectName.c_str(), GetFileDir(mTargetPath).c_str()); if (mIsCERun) { - mCELibProject = BfSystem_CreateProject(mSystem, "BeefLib"); + mCELibProject = BfSystem_CreateProject(mSystem, "BeefLib", GetFileDir(mTargetPath).c_str()); BfProjectFlags flags = BfProjectFlags_None; BfProject_SetOptions(mCELibProject, BfTargetType_BeefLib, "", mDefines.c_str(), mOptLevel, 0, 0, 0, flags); From 397257eba274fa94f6580c8e3172dbf440b77cfc Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 20 Dec 2021 10:31:57 -0500 Subject: [PATCH 070/139] Fixed inferred-size const array error during autocomplete --- IDEHelper/Compiler/BfModule.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index d51544c7..83709dd6 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -3913,7 +3913,7 @@ void BfModule::ResolveConstField(BfTypeInstance* typeInstance, BfFieldInstance* if (isLet || isVar) fieldType = GetPrimitiveType(BfTypeCode_Var); else - fieldType = ResolveTypeRef(fieldDef->mTypeRef); + fieldType = ResolveTypeRef(fieldDef->mTypeRef,BfPopulateType_Identity, BfResolveTypeRefFlag_AllowInferredSizedArray); if (fieldType == NULL) fieldType = mContext->mBfObjectType; } From f53877dc6316506f5d654f3cdf932d16de5e86c8 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 20 Dec 2021 12:03:09 -0500 Subject: [PATCH 071/139] Fixed invalid autocomplete comptime generation --- IDEHelper/Compiler/BfModule.cpp | 7 ++++++- IDEHelper/Compiler/CeMachine.cpp | 28 ++++++++++++++++++++-------- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 83709dd6..a854ed66 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -8470,7 +8470,7 @@ void BfModule::InitTypeInst(BfTypedValue typedValue, BfScopeData* scopeData, boo mBfIRBuilder->PopulateType(typedValue.mType); auto vObjectAddr = mBfIRBuilder->CreateInBoundsGEP(typedValue.mValue, 0, 0); bool isAutocomplete = mCompiler->IsAutocomplete(); - + BfIRValue vDataRef; if (!isAutocomplete) { @@ -18478,6 +18478,11 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup) { BP_ZONE_F("BfModule::ProcessMethod %s", BP_DYN_STR(methodInstance->mMethodDef->mName.c_str())); + if (mIsComptimeModule) + { + BF_ASSERT(!mCompiler->IsAutocomplete()); + } + if (mAwaitingInitFinish) FinishInit(); diff --git a/IDEHelper/Compiler/CeMachine.cpp b/IDEHelper/Compiler/CeMachine.cpp index 33de381b..793e2a8d 100644 --- a/IDEHelper/Compiler/CeMachine.cpp +++ b/IDEHelper/Compiler/CeMachine.cpp @@ -5,6 +5,7 @@ #include "BfParser.h" #include "BfReducer.h" #include "BfExprEvaluator.h" +#include "BfResolvePass.h" #include "../Backend/BeIRCodeGen.h" #include "BeefySysLib/platform/PlatformHelper.h" @@ -1332,15 +1333,21 @@ void CeBuilder::Build() mCeMachine->mCeModule->mStaticFieldRefs.Clear(); int startFunctionCount = (int)beModule->mFunctions.size(); - ProcessMethod(methodInstance, &dupMethodInstance); + /// + { + BfAutoComplete* prevAutoComplete = NULL; + if (mCeMachine->mCeModule->mCompiler->mResolvePassData != NULL) + { + prevAutoComplete = mCeMachine->mCeModule->mCompiler->mResolvePassData->mAutoComplete; + mCeMachine->mCeModule->mCompiler->mResolvePassData->mAutoComplete = NULL; + } + ProcessMethod(methodInstance, &dupMethodInstance); + if (mCeMachine->mCeModule->mCompiler->mResolvePassData != NULL) + mCeMachine->mCeModule->mCompiler->mResolvePassData->mAutoComplete = prevAutoComplete; + } if (mCeFunction->mInitializeState == CeFunction::InitializeState_Initialized) return; - if (methodInstance->mMethodDef->mName == "DecodeToUTF8") - { - NOP; - } - if (!dupMethodInstance.mIRFunction) { mCeFunction->mFailed = true; @@ -4653,12 +4660,12 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* if (ceModule->mSystem->mPtrSize == 4) { int32 intVal = *(int32*)((uint8*)stackPtr + 0); - OutputDebugStrF("Debug Val: %d\n", intVal); + OutputDebugStrF("Debug Val: %d %X\n", intVal, intVal); } else { int64 intVal = *(int64*)((uint8*)stackPtr + 0); - OutputDebugStrF("Debug Val: %lld\n", intVal); + OutputDebugStrF("Debug Val: %lld %llX\n", intVal, intVal); } } else if (checkFunction->mFunctionKind == CeFunctionKind_GetReflectType) @@ -5379,6 +5386,11 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* ++instIdx; + if (ceFunction->mMethodInstance->mMethodDef->mName == "ReadAll") + { + NOP; + } + if (instIdx >= /*0xBC0*/0xBA0) { NOP; From 5fe3591bd729681b27c4667b815f91215340aed9 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 20 Dec 2021 12:11:44 -0500 Subject: [PATCH 072/139] Remove debug code --- IDEHelper/Compiler/CeMachine.cpp | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/IDEHelper/Compiler/CeMachine.cpp b/IDEHelper/Compiler/CeMachine.cpp index 793e2a8d..8ef30454 100644 --- a/IDEHelper/Compiler/CeMachine.cpp +++ b/IDEHelper/Compiler/CeMachine.cpp @@ -5385,23 +5385,6 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* } ++instIdx; - - if (ceFunction->mMethodInstance->mMethodDef->mName == "ReadAll") - { - NOP; - } - - if (instIdx >= /*0xBC0*/0xBA0) - { - NOP; - } - -// if (instIdx == 0x444) -// { -// _CrtCheckMemory(); -// NOP; -// } - CeOp op = CE_GETINST(CeOp); switch (op) { From 649aabcaeed64795d8ac2f87be5f57ec5b40fdf9 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 20 Dec 2021 15:06:37 -0500 Subject: [PATCH 073/139] Leave append buffers uninitialized --- BeefLibs/corlib/src/String.bf | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/BeefLibs/corlib/src/String.bf b/BeefLibs/corlib/src/String.bf index 70fc7b5b..d243f8de 100644 --- a/BeefLibs/corlib/src/String.bf +++ b/BeefLibs/corlib/src/String.bf @@ -72,7 +72,7 @@ namespace System { int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1); #unwarn - char8* addlPtr = append char8[bufferSize]*; + char8* addlPtr = append char8[bufferSize]*(?); mAllocSizeAndFlags = (uint_strsize)bufferSize + (int_strsize)sizeof(char8*); mLength = 0; } @@ -82,7 +82,7 @@ namespace System { let bufferSize = 16 - sizeof(char8*); #unwarn - char8* addlPtr = append char8[bufferSize]*; + char8* addlPtr = append char8[bufferSize]*(?); mAllocSizeAndFlags = (uint_strsize)bufferSize + (int_strsize)sizeof(char8*); mLength = 0; } @@ -93,7 +93,7 @@ namespace System let count = str.mLength; int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1); #unwarn - char8* addlPtr = append char8[bufferSize]*; + char8* addlPtr = append char8[bufferSize]*(?); Internal.MemCpy(Ptr, str.Ptr, count); mLength = count; mAllocSizeAndFlags = (uint_strsize)bufferSize + (int_strsize)sizeof(char8*); @@ -106,7 +106,7 @@ namespace System let count = str.mLength - offset; int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1); #unwarn - char8* addlPtr = append char8[bufferSize]*; + char8* addlPtr = append char8[bufferSize]*(?); let ptr = Ptr; let srcPtr = str.Ptr; for (int_strsize i = 0; i < count; i++) @@ -123,7 +123,7 @@ namespace System int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1); #unwarn - char8* addlPtr = append char8[bufferSize]*; + char8* addlPtr = append char8[bufferSize]*(?); let ptr = Ptr; let srcPtr = str.Ptr; for (int i = 0; i < count; i++) @@ -137,7 +137,7 @@ namespace System { int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1); #unwarn - char8* addlPtr = append char8[bufferSize]*; + char8* addlPtr = append char8[bufferSize]*(?); let ptr = Ptr; for (int_strsize i = 0; i < count; i++) ptr[i] = c; @@ -151,7 +151,7 @@ namespace System let count = Internal.CStrLen(char8Ptr); int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1); #unwarn - char8* addlPtr = append char8[bufferSize]*; + char8* addlPtr = append char8[bufferSize]*(?); let ptr = Ptr; for (int_strsize i = 0; i < count; i++) ptr[i] = char8Ptr[i]; @@ -164,7 +164,7 @@ namespace System { int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1); #unwarn - char8* addlPtr = append char8[bufferSize]*; + char8* addlPtr = append char8[bufferSize]*(?); let ptr = Ptr; for (int i = 0; i < count; i++) ptr[i] = char8Ptr[i]; @@ -178,7 +178,7 @@ namespace System let count = UTF16.GetLengthAsUTF8(char16Ptr); int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1); #unwarn - char8* addlPtr = append char8[bufferSize]*; + char8* addlPtr = append char8[bufferSize]*(?); mAllocSizeAndFlags = (uint_strsize)bufferSize + (int_strsize)sizeof(char8*); mLength = 0; UTF16.Decode(char16Ptr, this); @@ -190,7 +190,7 @@ namespace System let count = UTF16.GetLengthAsUTF8(chars); int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1); #unwarn - char8* addlPtr = append char8[bufferSize]*; + char8* addlPtr = append char8[bufferSize]*(?); mAllocSizeAndFlags = (uint_strsize)bufferSize + (int_strsize)sizeof(char8*); mLength = 0; UTF16.Decode(chars, this); @@ -202,7 +202,7 @@ namespace System let tryBufferSize = strView.Length - sizeof(char8*); let bufferSize = (tryBufferSize >= 0) ? tryBufferSize : 0; #unwarn - char8* addlPtr = append char8[bufferSize]*; + char8* addlPtr = append char8[bufferSize]*(?); let ptr = Ptr; Internal.MemCpy(ptr, strView.Ptr, strView.Length); mAllocSizeAndFlags = (uint_strsize)bufferSize + (int_strsize)sizeof(char8*); @@ -215,7 +215,7 @@ namespace System let count = strView.Length + (flags.HasFlag(.NullTerminate) ? 1 : 0); int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1); #unwarn - char8* addlPtr = append char8[bufferSize]*; + char8* addlPtr = append char8[bufferSize]*(?); let ptr = Ptr; Internal.MemCpy(ptr, strView.Ptr, strView.Length); if (flags.HasFlag(.NullTerminate)) @@ -232,7 +232,7 @@ namespace System let count = strView.Length - offset; int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1); #unwarn - char8* addlPtr = append char8[bufferSize]*; + char8* addlPtr = append char8[bufferSize]*(?); let ptr = Ptr; let srcPtr = strView.Ptr; for (int i = 0; i < count; i++) @@ -249,7 +249,7 @@ namespace System int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1); #unwarn - char8* addlPtr = append char8[bufferSize]*; + char8* addlPtr = append char8[bufferSize]*(?); let ptr = Ptr; let srcPtr = strView.Ptr; for (int i = 0; i < count; i++) @@ -263,7 +263,7 @@ namespace System { int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1); #unwarn - char8* addlPtr = append char8[bufferSize]*; + char8* addlPtr = append char8[bufferSize]*(?); let ptr = Ptr; for (int i = 0; i < count; i++) ptr[i] = chars[i + offset]; @@ -285,7 +285,7 @@ namespace System int count = StrLengths(strs); int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1); #unwarn - char8* addlPtr = append char8[bufferSize]*; + char8* addlPtr = append char8[bufferSize]*(?); let ptr = Ptr; int curIdx = 0; for (var str in strs) From 2f72311f1fa24ab14e2f6a47f75c5d6d9f725590 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 20 Dec 2021 15:07:38 -0500 Subject: [PATCH 074/139] Const string alloc fixes, large string fixes, mem range check fix --- IDEHelper/Compiler/BfModule.cpp | 2 +- IDEHelper/Compiler/CeMachine.cpp | 108 ++++++++++++++++++++++++------- IDEHelper/Compiler/CeMachine.h | 10 +-- IDEHelper/Tests/src/Comptime.bf | 3 + 4 files changed, 95 insertions(+), 28 deletions(-) diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index a854ed66..2f4cad4f 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -8473,7 +8473,7 @@ void BfModule::InitTypeInst(BfTypedValue typedValue, BfScopeData* scopeData, boo BfIRValue vDataRef; if (!isAutocomplete) - { + { vDataRef = GetClassVDataPtr(typeInstance); } diff --git a/IDEHelper/Compiler/CeMachine.cpp b/IDEHelper/Compiler/CeMachine.cpp index 8ef30454..dfadf026 100644 --- a/IDEHelper/Compiler/CeMachine.cpp +++ b/IDEHelper/Compiler/CeMachine.cpp @@ -1282,6 +1282,12 @@ void CeBuilder::HandleParams() void CeBuilder::ProcessMethod(BfMethodInstance* methodInstance, BfMethodInstance* dupMethodInstance) { SetAndRestoreValue prevMethodStateInConstEval(mCeMachine->mCeModule->mCurMethodState, NULL); + BfAutoComplete* prevAutoComplete = NULL; + if (mCeMachine->mCeModule->mCompiler->mResolvePassData != NULL) + { + prevAutoComplete = mCeMachine->mCeModule->mCompiler->mResolvePassData->mAutoComplete; + mCeMachine->mCeModule->mCompiler->mResolvePassData->mAutoComplete = NULL; + } auto irCodeGen = mCeMachine->mCeModule->mBfIRBuilder->mBeIRCodeGen; auto irBuilder = mCeMachine->mCeModule->mBfIRBuilder; @@ -1296,6 +1302,9 @@ void CeBuilder::ProcessMethod(BfMethodInstance* methodInstance, BfMethodInstance mCeMachine->mCeModule->ProcessMethod(dupMethodInstance, true); irCodeGen->SetState(beState); irBuilder->SetState(irState); + + if (mCeMachine->mCeModule->mCompiler->mResolvePassData != NULL) + mCeMachine->mCeModule->mCompiler->mResolvePassData->mAutoComplete = prevAutoComplete; } void CeBuilder::Build() @@ -1333,18 +1342,7 @@ void CeBuilder::Build() mCeMachine->mCeModule->mStaticFieldRefs.Clear(); int startFunctionCount = (int)beModule->mFunctions.size(); - /// - { - BfAutoComplete* prevAutoComplete = NULL; - if (mCeMachine->mCeModule->mCompiler->mResolvePassData != NULL) - { - prevAutoComplete = mCeMachine->mCeModule->mCompiler->mResolvePassData->mAutoComplete; - mCeMachine->mCeModule->mCompiler->mResolvePassData->mAutoComplete = NULL; - } - ProcessMethod(methodInstance, &dupMethodInstance); - if (mCeMachine->mCeModule->mCompiler->mResolvePassData != NULL) - mCeMachine->mCeModule->mCompiler->mResolvePassData->mAutoComplete = prevAutoComplete; - } + ProcessMethod(methodInstance, &dupMethodInstance); if (mCeFunction->mInitializeState == CeFunction::InitializeState_Initialized) return; @@ -2905,6 +2903,7 @@ CeContext::CeContext() mCeMachine = NULL; mReflectTypeIdOffset = -1; mExecuteId = -1; + mStackSize = -1; mCurTargetSrc = NULL; mHeap = new ContiguousHeap(); @@ -3045,7 +3044,7 @@ uint8* CeContext::CeMalloc(int size) { #ifdef CE_ENABLE_HEAP auto heapRef = mHeap->Alloc(size); - auto ceAddr = BF_CE_STACK_SIZE + heapRef; + auto ceAddr = mStackSize + heapRef; int sizeDelta = (ceAddr + size) - mMemory.mSize; if (sizeDelta > 0) mMemory.GrowUninitialized(sizeDelta); @@ -3058,7 +3057,7 @@ uint8* CeContext::CeMalloc(int size) bool CeContext::CeFree(addr_ce addr) { #ifdef CE_ENABLE_HEAP - ContiguousHeap::AllocRef heapRef = addr - BF_CE_STACK_SIZE; + ContiguousHeap::AllocRef heapRef = addr - mStackSize; return mHeap->Free(heapRef); #else return true; @@ -3747,6 +3746,19 @@ BfIRValue CeContext::CreateConstant(BfModule* module, uint8* ptr, BfType* bfType charPtr = (char*)(instData + ptrOffset); } } + else + { + int64 allocSizeVal = *(int64*)(instData + allocSizeOffset); + if ((allocSizeVal & 0x4000000000000000LL) != 0) + { + int32 ptrVal = *(int32*)(instData + ptrOffset); + charPtr = (char*)(ptrVal + memStart); + } + else + { + charPtr = (char*)(instData + ptrOffset); + } + } CE_CREATECONST_CHECKPTR(charPtr, lenVal); String str(charPtr, lenVal); @@ -4130,7 +4142,7 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns if (ceFunction->mInitializeState < CeFunction::InitializeState_Initialized) mCeMachine->PrepareFunction(ceFunction, NULL); - auto stackPtr = &mMemory[0] + BF_CE_STACK_SIZE; + auto stackPtr = &mMemory[0] + mStackSize; auto* memStart = &mMemory[0]; BfTypeInstance* thisType = methodInstance->GetOwner(); @@ -4152,6 +4164,23 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns allocThisSize += appendSizeConstant->mInt32; } + if (allocThisSize >= mStackSize / 4) + { + // Resize stack a reasonable size + mStackSize = BF_ALIGN(allocThisSize, 0x100000) + BF_CE_DEFAULT_STACK_SIZE; + int64 memSize = mStackSize + BF_CE_DEFAULT_HEAP_SIZE; + if (memSize > BF_CE_MAX_MEMORY) + { + Fail("Return value too large (>2GB)"); + return BfTypedValue(); + } + + if (memSize > mMemory.mSize) + mMemory.Resize(memSize); + stackPtr = &mMemory[0] + mStackSize; + memStart = &mMemory[0]; + } + stackPtr -= allocThisSize; auto allocThisPtr = stackPtr; memset(allocThisPtr, 0, allocThisSize); @@ -4168,6 +4197,7 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns { stackPtr -= ceModule->mSystem->mPtrSize; memset(stackPtr, 0, ceModule->mSystem->mPtrSize); + *(addr_ce*)(stackPtr) = (addr_ce)(allocThisInstAddr + thisType->mInstSize); allocAppendIdxAddr = stackPtr - memStart; } @@ -4301,7 +4331,14 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns } BfType* usedReturnType = returnType; - BfIRValue constVal = CreateConstant(module, retPtr, returnType, &usedReturnType); + BfIRValue constVal; + if (returnType->IsObject()) + { + addr_ce retAddr = retPtr - memStart; + constVal = CreateConstant(module, (uint8*)&retAddr, returnType, &usedReturnType); + } + else + constVal = CreateConstant(module, retPtr, returnType, &usedReturnType); if (constVal) returnValue = BfTypedValue(constVal, usedReturnType); else @@ -4334,9 +4371,10 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns } #define CE_CHECKALLOC(SIZE) \ - if ((SIZE < 0) || (uintptr)memSize + (uintptr)SIZE > BF_CE_MAX_MEMORY) \ + if ((SIZE < 0) || (SIZE >= 0x80000000LL) || ((uintptr)memSize + (uintptr)SIZE > BF_CE_MAX_MEMORY)) \ { \ - _Fail("Maximum memory size exceeded"); \ + _Fail("Maximum memory size exceeded (2GB)"); \ + return false; \ } // This check will fail for addresses < 64K (null pointer), or out-of-bounds @@ -4347,7 +4385,7 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns return false; \ } #define CE_CHECKADDR(ADDR, SIZE) \ - if (((ADDR) - 0x10000) + (SIZE) > (memSize - 0x10000)) \ + if (((ADDR) < 0x10000) || ((ADDR) + (SIZE) > memSize)) \ { \ _Fail("Access violation"); \ return false; \ @@ -4588,7 +4626,11 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* } else if (checkFunction->mFunctionKind == CeFunctionKind_Malloc) { - int32 size = *(int32*)((uint8*)stackPtr + 4); + int64 size; + if (ptrSize == 4) + size = *(int32*)((uint8*)stackPtr + 4); + else + size = *(int64*)((uint8*)stackPtr + 8); CE_CHECKALLOC(size); uint8* ptr = CeMalloc(size); CeSetAddrVal(stackPtr + 0, ptr - memStart, ptrSize); @@ -4630,6 +4672,19 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* charPtr = (char*)(strInst + ptrOffset); } } + else + { + int64 allocSizeVal = *(int64*)(strInst + allocSizeOffset); + if ((allocSizeVal & 0x4000000000000000LL) != 0) + { + int32 ptrVal = *(int32*)(strInst + ptrOffset); + charPtr = (char*)(ptrVal + memStart); + } + else + { + charPtr = (char*)(strInst + ptrOffset); + } + } int32 ptrVal = *(int32*)(strInst + ptrOffset); @@ -4671,7 +4726,7 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* else if (checkFunction->mFunctionKind == CeFunctionKind_GetReflectType) { addr_ce objAddr = *(addr_ce*)((uint8*)stackPtr + ceModule->mSystem->mPtrSize); - CE_CHECKADDR(addr_ce, 4); + CE_CHECKADDR(objAddr, 4); int32 typeId = *(int32*)(objAddr + memStart); auto reflectType = GetReflectType(typeId); @@ -5370,6 +5425,8 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* int callCount = 0; int instIdx = 0; + CE_CHECKSTACK(); + while (true) { if (*fastFinishPtr) @@ -5512,7 +5569,11 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* case CeOp_Malloc: { auto frameOfs = CE_GETINST(int32); - int32 size = CE_GETFRAME(int32); + int64 size; + if (ptrSize == 4) + size = CE_GETFRAME(int32); + else + size = CE_GETFRAME(int64); CE_CHECKALLOC(size); uint8* mem = CeMalloc(size); _FixVariables(); @@ -7632,7 +7693,8 @@ CeContext* CeMachine::AllocContext() ceContext->mCurEmitContext = mCurEmitContext; mCurEmitContext = NULL; mExecuteId++; - ceContext->mMemory.Resize(BF_CE_STACK_SIZE); + ceContext->mStackSize = BF_CE_DEFAULT_STACK_SIZE; + ceContext->mMemory.Resize(ceContext->mStackSize); ceContext->mExecuteId = mExecuteId; ceContext->mCurHandleId = 0; return ceContext; diff --git a/IDEHelper/Compiler/CeMachine.h b/IDEHelper/Compiler/CeMachine.h index c8eef486..f58aa3ab 100644 --- a/IDEHelper/Compiler/CeMachine.h +++ b/IDEHelper/Compiler/CeMachine.h @@ -547,10 +547,11 @@ public: } }; -#define BF_CE_STACK_SIZE 4*1024*1024 -#define BF_CE_INITIAL_MEMORY BF_CE_STACK_SIZE + 128*1024 -#define BF_CE_MAX_MEMORY 128*1024*1024 -#define BF_CE_MAX_CARRYOVER_MEMORY BF_CE_STACK_SIZE * 2 +#define BF_CE_DEFAULT_STACK_SIZE 4*1024*1024 +#define BF_CE_DEFAULT_HEAP_SIZE 128*1024 +#define BF_CE_INITIAL_MEMORY BF_CE_DEFAULT_STACK_SIZE + BF_CE_DEFAULT_HEAP_SIZE +#define BF_CE_MAX_MEMORY 0x7FFFFFFF +#define BF_CE_MAX_CARRYOVER_MEMORY BF_CE_DEFAULT_STACK_SIZE * 2 #define BF_CE_MAX_CARRYOVER_HEAP 1024*1024 enum CeOperandInfoKind @@ -812,6 +813,7 @@ public: ContiguousHeap* mHeap; Array mCallStack; Array mMemory; + int mStackSize; Dictionary mStringMap; Dictionary mReflectMap; Dictionary mConstDataMap; diff --git a/IDEHelper/Tests/src/Comptime.bf b/IDEHelper/Tests/src/Comptime.bf index 55bfb785..7434fe8f 100644 --- a/IDEHelper/Tests/src/Comptime.bf +++ b/IDEHelper/Tests/src/Comptime.bf @@ -231,6 +231,7 @@ namespace Tests } const String cTest0 = Compiler.ReadText("Test0.txt"); + const String cTest1 = new String('A', 12); const uint8[?] cTest0Binary = Compiler.ReadBinary("Test0.txt"); [Test] @@ -275,6 +276,8 @@ namespace Tests Test.Assert(serCtx.mStr == "x 10\ny 2\n"); Test.Assert(cTest0 == "Test\n0"); + Test.Assert(cTest1 == "AAAAAAAAAAAA"); + Test.Assert((Object)cTest1 == (Object)"AAAAAAAAAAAA"); Test.Assert((cTest0Binary[0] == (.)'T') && ((cTest0Binary.Count == 6) || (cTest0Binary.Count == 7))); } } From 1d621f5d313d9a9b29325680bff56dce5e204c08 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 20 Dec 2021 15:24:25 -0500 Subject: [PATCH 075/139] BfpSpawn_Create fixes --- IDEHelper/Compiler/CeMachine.cpp | 33 ++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/IDEHelper/Compiler/CeMachine.cpp b/IDEHelper/Compiler/CeMachine.cpp index dfadf026..c9ff290b 100644 --- a/IDEHelper/Compiler/CeMachine.cpp +++ b/IDEHelper/Compiler/CeMachine.cpp @@ -5266,26 +5266,35 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* addr_ce workingDirAddr = *(addr_ce*)((uint8*)stackPtr + ptrSize + ptrSize + ptrSize); addr_ce envAddr = *(addr_ce*)((uint8*)stackPtr + ptrSize + ptrSize + ptrSize + ptrSize); int flags = *(int*)((uint8*)stackPtr + ptrSize + ptrSize + ptrSize + ptrSize + ptrSize); - addr_ce outResultAddr = *(addr_ce*)((uint8*)stackPtr + ptrSize + ptrSize + ptrSize + ptrSize + ptrSize + ptrSize); + addr_ce outResultAddr = *(addr_ce*)((uint8*)stackPtr + ptrSize + ptrSize + ptrSize + ptrSize + ptrSize + 4); String targetPath; CE_CHECKADDR_STR(targetPath, targetPathAddr); String args; - CE_CHECKADDR_STR(args, argsAddr); + if (argsAddr != 0) + CE_CHECKADDR_STR(args, argsAddr); String workingDir; - CE_CHECKADDR_STR(workingDir, workingDirAddr); + if (workingDirAddr != 0) + CE_CHECKADDR_STR(workingDir, workingDirAddr); String env; - CE_CHECKADDR_STR(env, envAddr); + if (envAddr != 0) + CE_CHECKADDR_STR(env, envAddr); CE_CHECKADDR(outResultAddr, 4); + + if ((targetPath.Contains('/')) || (targetPath.Contains('\\'))) + { + BfProject* activeProject = NULL; + auto activeTypeDef = mCurModule->GetActiveTypeDef(); + if (activeTypeDef != NULL) + activeProject = activeTypeDef->mProject; + if (activeProject != NULL) + targetPath = GetAbsPath(targetPath, activeProject->mDirectory); + } - BfProject* activeProject = NULL; - auto activeTypeDef = mCurModule->GetActiveTypeDef(); - if (activeTypeDef != NULL) - activeProject = activeTypeDef->mProject; - if (activeProject != NULL) - targetPath = GetAbsPath(targetPath, activeProject->mDirectory); - - auto bfpSpawn = BfpSpawn_Create(targetPath.c_str(), args.c_str(), workingDir.c_str(), env.c_str(), (BfpSpawnFlags)flags, (BfpSpawnResult*)(memStart + outResultAddr)); + auto bfpSpawn = BfpSpawn_Create(targetPath.c_str(), + (argsAddr == 0) ? NULL : args.c_str(), + (workingDirAddr == 0) ? NULL : workingDir.c_str(), + (envAddr == 0) ? NULL : env.c_str(), (BfpSpawnFlags)flags, (BfpSpawnResult*)(memStart + outResultAddr)); if (bfpSpawn != NULL) { CeInternalData* internalData = new CeInternalData(); From 5c320fa9c9daebf971af448450559d35acd39ae4 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 20 Dec 2021 15:37:01 -0500 Subject: [PATCH 076/139] Fixed exit code --- IDEHelper/Compiler/CeMachine.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/IDEHelper/Compiler/CeMachine.cpp b/IDEHelper/Compiler/CeMachine.cpp index c9ff290b..8517ad00 100644 --- a/IDEHelper/Compiler/CeMachine.cpp +++ b/IDEHelper/Compiler/CeMachine.cpp @@ -5255,7 +5255,7 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* CeInternalData* internalData = NULL; CE_GET_INTERNAL(internalData, (int)fileId, CeInternalData::Kind_File); - int64 result = BfpFile_Write(internalData->mFile, memStart + bufferPtr, bufferSize, timeoutMS, (BfpFileResult*)(memStart + outResultAddr)); + int64 result = BfpFile_Write(internalData->mFile, memStart + bufferPtr, bufferSize, timeoutMS, (outResultAddr == 0) ? NULL : (BfpFileResult*)(memStart + outResultAddr)); CeSetAddrVal(resultPtr, result, ptrSize); } else if (checkFunction->mFunctionKind == CeFunctionKind_BfpSpawn_Create) @@ -5294,7 +5294,7 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* auto bfpSpawn = BfpSpawn_Create(targetPath.c_str(), (argsAddr == 0) ? NULL : args.c_str(), (workingDirAddr == 0) ? NULL : workingDir.c_str(), - (envAddr == 0) ? NULL : env.c_str(), (BfpSpawnFlags)flags, (BfpSpawnResult*)(memStart + outResultAddr)); + (envAddr == 0) ? NULL : env.c_str(), (BfpSpawnFlags)flags, (outResultAddr == 0) ? NULL : (BfpSpawnResult*)(memStart + outResultAddr)); if (bfpSpawn != NULL) { CeInternalData* internalData = new CeInternalData(); @@ -5375,11 +5375,13 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* addr_ce outResultAddr = *(addr_ce*)((uint8*)stackPtr + 1 + ptrSize + ptrSize + ptrSize); CE_CHECKADDR(outExitCodeAddr, ptrSize); - CE_CHECKADDR(outResultAddr, 4); + if (outResultAddr != 0) + CE_CHECKADDR(outResultAddr, 4); CeInternalData* internalData = NULL; CE_GET_INTERNAL(internalData, (int)spawnId, CeInternalData::Kind_Spawn); + int outExitCode = 0; int timeLeft = waitMS; do { @@ -5395,14 +5397,14 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* waitTime = BF_MIN(timeLeft, 20); timeLeft -= waitTime; } - - int outExitCode = 0; - result = BfpSpawn_WaitFor(internalData->mSpawn, waitTime, &outExitCode, (BfpSpawnResult*)(memStart + outResultAddr)); + + result = BfpSpawn_WaitFor(internalData->mSpawn, waitTime, &outExitCode, (outResultAddr == 0) ? NULL : (BfpSpawnResult*)(memStart + outResultAddr)); if (result) break; if (waitTime == 0) break; } while (true); + *(int*)(memStart + outExitCodeAddr) = outExitCode; } else { From acc2e5b14c3ecc56703233631e18cdaa2a1e9c7d Mon Sep 17 00:00:00 2001 From: unknown <81806010+marsej@users.noreply.github.com> Date: Tue, 21 Dec 2021 10:55:40 +0200 Subject: [PATCH 077/139] Add option for configuring mMaxCol with mWrapCommentsAt --- IDE/src/Compiler/BfParser.bf | 4 ++-- IDE/src/Settings.bf | 3 +++ IDE/src/ui/SettingsDialog.bf | 2 +- IDEHelper/Compiler/BfParser.cpp | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/IDE/src/Compiler/BfParser.bf b/IDE/src/Compiler/BfParser.bf index 34a00e27..8505e5f7 100644 --- a/IDE/src/Compiler/BfParser.bf +++ b/IDE/src/Compiler/BfParser.bf @@ -120,7 +120,7 @@ namespace IDE.Compiler static extern bool BfParser_Reduce(void* bfParser, void* bfPassInstance); [CallingConvention(.Stdcall), CLink] - static extern char8* BfParser_Format(void* bfParser, int32 formatEnd, int32 formatStart, out int32* outCharMapping); + static extern char8* BfParser_Format(void* bfParser, int32 formatEnd, int32 formatStart, out int32* outCharMapping, int32 maxCol); [CallingConvention(.Stdcall), CLink] static extern char8* BfParser_GetDebugExpressionAt(void* bfParser, int32 cursorIdx); @@ -207,7 +207,7 @@ namespace IDE.Compiler public void Reformat(int formatStart, int formatEnd, out int32[] char8Mapping, String str) { int32* char8MappingPtr; - var stringPtr = BfParser_Format(mNativeBfParser, (int32)formatStart, (int32)formatEnd, out char8MappingPtr); + var stringPtr = BfParser_Format(mNativeBfParser, (int32)formatStart, (int32)formatEnd, out char8MappingPtr, gApp.mSettings.mEditorSettings.mWrapCommentsAt); str.Append(stringPtr); char8Mapping = new int32[str.Length]; diff --git a/IDE/src/Settings.bf b/IDE/src/Settings.bf index 6065643e..712f6d45 100644 --- a/IDE/src/Settings.bf +++ b/IDE/src/Settings.bf @@ -625,6 +625,7 @@ namespace IDE public FileRecoveryKind mEnableFileRecovery = .Yes; public bool mFormatOnSave = false; public bool mSyncWithWorkspacePanel = false; + public int32 mWrapCommentsAt = 0; public void Serialize(StructuredData sd) { @@ -650,6 +651,7 @@ namespace IDE sd.Add("EnableFileRecovery", mEnableFileRecovery); sd.Add("FormatOnSave", mFormatOnSave); sd.Add("SyncWithWorkspacePanel", mSyncWithWorkspacePanel); + sd.Add("WrapCommentsAt", mWrapCommentsAt); } public void Deserialize(StructuredData sd) @@ -679,6 +681,7 @@ namespace IDE sd.GetEnum("EnableFileRecovery", ref mEnableFileRecovery); sd.Get("FormatOnSave", ref mFormatOnSave); sd.Get("SyncWithWorkspacePanel", ref mSyncWithWorkspacePanel); + sd.Get("WrapCommentsAt", ref mWrapCommentsAt); } public void SetDefaults() diff --git a/IDE/src/ui/SettingsDialog.bf b/IDE/src/ui/SettingsDialog.bf index 38cf60b3..3cd02120 100644 --- a/IDE/src/ui/SettingsDialog.bf +++ b/IDE/src/ui/SettingsDialog.bf @@ -126,7 +126,7 @@ namespace IDE.ui AddPropertiesItem(category, "Enable File Recovery", "mEnableFileRecovery"); AddPropertiesItem(category, "Format on Save", "mFormatOnSave"); AddPropertiesItem(category, "Sync with Workspace Panel", "mSyncWithWorkspacePanel"); - + AddPropertiesItem(category, "Wrap comments at length (0 = none)", "mWrapCommentsAt"); category.Open(true, true); } diff --git a/IDEHelper/Compiler/BfParser.cpp b/IDEHelper/Compiler/BfParser.cpp index e96ba38f..060fe028 100644 --- a/IDEHelper/Compiler/BfParser.cpp +++ b/IDEHelper/Compiler/BfParser.cpp @@ -3800,13 +3800,14 @@ BF_EXPORT bool BF_CALLTYPE BfParser_Reduce(BfParser* bfParser, BfPassInstance* b } static Array gCharMapping; -BF_EXPORT const char* BF_CALLTYPE BfParser_Format(BfParser* bfParser, int formatStart, int formatEnd, int** outCharMapping) +BF_EXPORT const char* BF_CALLTYPE BfParser_Format(BfParser* bfParser, int formatStart, int formatEnd, int** outCharMapping, int maxCol) { BP_ZONE("BfParser_Reduce"); String& outString = *gTLStrReturn.Get(); outString.clear(); gCharMapping.Clear(); BfPrinter bfPrinter(bfParser->mRootNode, bfParser->mSidechannelRootNode, bfParser->mErrorRootNode); + bfPrinter.mMaxCol = maxCol; bfPrinter.mFormatStart = formatStart; bfPrinter.mFormatEnd = formatEnd; bfPrinter.mCharMapping = &gCharMapping; From 3a25b8385fbe43efcd40fd372f498d8e97f9a984 Mon Sep 17 00:00:00 2001 From: unknown <81806010+marsej@users.noreply.github.com> Date: Tue, 21 Dec 2021 11:12:32 +0200 Subject: [PATCH 078/139] minor fix --- IDE/src/Compiler/BfParser.bf | 7 ++++--- IDE/src/ui/SettingsDialog.bf | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/IDE/src/Compiler/BfParser.bf b/IDE/src/Compiler/BfParser.bf index 8505e5f7..dfb0d967 100644 --- a/IDE/src/Compiler/BfParser.bf +++ b/IDE/src/Compiler/BfParser.bf @@ -120,7 +120,7 @@ namespace IDE.Compiler static extern bool BfParser_Reduce(void* bfParser, void* bfPassInstance); [CallingConvention(.Stdcall), CLink] - static extern char8* BfParser_Format(void* bfParser, int32 formatEnd, int32 formatStart, out int32* outCharMapping, int32 maxCol); + static extern char8* BfParser_Format(void* bfParser, int32 formatEnd, int32 formatStart, out int32* outCharMapping, int32 maxCol); [CallingConvention(.Stdcall), CLink] static extern char8* BfParser_GetDebugExpressionAt(void* bfParser, int32 cursorIdx); @@ -207,8 +207,9 @@ namespace IDE.Compiler public void Reformat(int formatStart, int formatEnd, out int32[] char8Mapping, String str) { int32* char8MappingPtr; - var stringPtr = BfParser_Format(mNativeBfParser, (int32)formatStart, (int32)formatEnd, out char8MappingPtr, gApp.mSettings.mEditorSettings.mWrapCommentsAt); - str.Append(stringPtr); + var maxCol = gApp.mSettings.mEditorSettings.mWrapCommentsAt; + var stringPtr = BfParser_Format(mNativeBfParser, (int32)formatStart, (int32)formatEnd, out char8MappingPtr, maxCol); + str.Append(stringPtr); char8Mapping = new int32[str.Length]; for (int32 i = 0; i < char8Mapping.Count; i++) diff --git a/IDE/src/ui/SettingsDialog.bf b/IDE/src/ui/SettingsDialog.bf index 3cd02120..f4f305b5 100644 --- a/IDE/src/ui/SettingsDialog.bf +++ b/IDE/src/ui/SettingsDialog.bf @@ -127,6 +127,7 @@ namespace IDE.ui AddPropertiesItem(category, "Format on Save", "mFormatOnSave"); AddPropertiesItem(category, "Sync with Workspace Panel", "mSyncWithWorkspacePanel"); AddPropertiesItem(category, "Wrap comments at length (0 = none)", "mWrapCommentsAt"); + category.Open(true, true); } From 1155bd9600876cdae8693b3bacb90cca122a3201 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 21 Dec 2021 07:13:47 -0500 Subject: [PATCH 079/139] Editor fixes --- IDE/src/IDEApp.bf | 15 +++++++++++++-- IDE/src/ui/OutputPanel.bf | 3 ++- IDE/src/ui/SourceEditWidgetContent.bf | 3 +++ IDE/src/ui/SourceViewPanel.bf | 12 ++++++------ 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/IDE/src/IDEApp.bf b/IDE/src/IDEApp.bf index 103c65fd..dc719197 100644 --- a/IDE/src/IDEApp.bf +++ b/IDE/src/IDEApp.bf @@ -2314,6 +2314,11 @@ namespace IDE widget.RemoveSelf(); } + WithSourceViewPanels(scope (sourceViewPanel) => + { + sourceViewPanel.Dispose(); + }); + if (!mRunningTestScript) { mActiveDocumentsTabbedView = null; @@ -5712,14 +5717,20 @@ namespace IDE { let sewc = editWidget.mEditWidgetContent as SourceEditWidgetContent; if (sewc != null) - return sewc; + { + if (sewc.mEditWidget.mHasFocus) + return sewc; + return null; + } } } var activeTextPanel = GetActivePanel() as TextPanel; if (activeTextPanel != null) { - return activeTextPanel.EditWidget.mEditWidgetContent as SourceEditWidgetContent; + let sewc = activeTextPanel.EditWidget.mEditWidgetContent as SourceEditWidgetContent; + if ((sewc != null) && (sewc.mEditWidget.mHasFocus)) + return sewc; } return null; diff --git a/IDE/src/ui/OutputPanel.bf b/IDE/src/ui/OutputPanel.bf index e99e10a6..a60696f8 100644 --- a/IDE/src/ui/OutputPanel.bf +++ b/IDE/src/ui/OutputPanel.bf @@ -139,7 +139,8 @@ namespace IDE.ui mOutputWidget.SetText(""); for (var widgetEntry in mInlineWidgets) { - widgetEntry.mWidget.RemoveSelf(); + if (widgetEntry.mWidget.mParent != null) + widgetEntry.mWidget.RemoveSelf(); delete widgetEntry.mWidget; } mInlineWidgets.Clear(); diff --git a/IDE/src/ui/SourceEditWidgetContent.bf b/IDE/src/ui/SourceEditWidgetContent.bf index dbb19ef7..1a91924f 100644 --- a/IDE/src/ui/SourceEditWidgetContent.bf +++ b/IDE/src/ui/SourceEditWidgetContent.bf @@ -2275,6 +2275,9 @@ namespace IDE.ui public void DuplicateLine() { + if ((CheckReadOnly()) || (!mAllowVirtualCursor)) + return; + UndoBatchStart undoBatchStart = new UndoBatchStart("duplicateLine"); mData.mUndoManager.Add(undoBatchStart); diff --git a/IDE/src/ui/SourceViewPanel.bf b/IDE/src/ui/SourceViewPanel.bf index 6e814b31..c1d98643 100644 --- a/IDE/src/ui/SourceViewPanel.bf +++ b/IDE/src/ui/SourceViewPanel.bf @@ -546,11 +546,6 @@ namespace IDE.ui public ~this() { - if (mProjectSource?.mEditData?.HasTextChanged() == true) - { - mProjectSource.ClearEditData(); - } - if (mInPostRemoveUpdatePanels) { //Debug.WriteLine("Removing sourceViewPanel from mPostRemoveUpdatePanel {0} in ~this ", this); @@ -1185,7 +1180,7 @@ namespace IDE.ui //if (mCurParser != null) { if (gApp.mWorkspace.mProjectLoadState != .Loaded) - return false; + return true; if (!isHi) Debug.Assert(!mIsPerformingBackgroundClassify); @@ -2333,6 +2328,11 @@ namespace IDE.ui if (mDisposed) return; + if (mProjectSource?.mEditData?.HasTextChanged() == true) + { + mProjectSource.ClearEditData(); + } + ProcessDeferredResolveResults(-1); if (IDEApp.sApp.mLastActiveSourceViewPanel == this) From c06b4eb946dd8f3e2afa72b1cc6839ba0b2e94b1 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 21 Dec 2021 07:14:46 -0500 Subject: [PATCH 080/139] Comment formatting fixes --- IDEHelper/Compiler/BfPrinter.cpp | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/IDEHelper/Compiler/BfPrinter.cpp b/IDEHelper/Compiler/BfPrinter.cpp index f30db3a9..a5e473df 100644 --- a/IDEHelper/Compiler/BfPrinter.cpp +++ b/IDEHelper/Compiler/BfPrinter.cpp @@ -300,11 +300,8 @@ int BfPrinter::CalcOrigLineSpacing(BfAstNode* bfAstNode, int* lineStartIdx) void BfPrinter::WriteIgnoredNode(BfAstNode* node) { - if ((!mOutString.IsEmpty()) && (!isspace((uint8)mOutString[mOutString.mLength - 1]))) - { - Write(" "); - } - + bool startsWithSpace = false; + bool wasExpectingNewLine = mExpectingNewLine; mTriviaIdx = std::max(mTriviaIdx, node->GetTriviaStart()); @@ -315,12 +312,17 @@ void BfPrinter::WriteIgnoredNode(BfAstNode* node) for (int i = mTriviaIdx; i < srcEnd; i++) { char c = astNodeSrc->mSrc[i]; + if ((i == mTriviaIdx) && (isspace((uint8)c))) + startsWithSpace = true; + if ((c == '\n') && (i < node->GetSrcStart())) crCount++; if (((c != ' ') && (c != '\t')) || (!mReformatting)) endIdx = i + 1; } + bool wantsPrefixSpace = (!mOutString.IsEmpty()) && (!isspace((uint8)mOutString[mOutString.mLength - 1])); + bool expectingNewLine = mNextStateModify.mWantNewLineIdx != mVirtualNewLineIdx; int startIdx = mTriviaIdx; @@ -333,7 +335,10 @@ void BfPrinter::WriteIgnoredNode(BfAstNode* node) if ((origLineSpacing != -1) && (lineStart != -1)) { for (int i = 0; i < crCount; i++) + { Write("\n"); + wantsPrefixSpace = false; + } startIdx = node->GetSrcStart(); // Leave left-aligned preprocessor nodes if ((node->GetSourceData()->mSrc[node->GetSrcStart()] != '#') || (origLineSpacing > 0)) @@ -439,6 +444,10 @@ void BfPrinter::WriteIgnoredNode(BfAstNode* node) bool emitChar = true; char c = astNodeSrc->mSrc[srcIdx]; + + if ((wantsPrefixSpace) && (isspace((uint8)c))) + wantsPrefixSpace = false; + if (c == '\n') { isNewLine = true; @@ -592,7 +601,12 @@ void BfPrinter::WriteIgnoredNode(BfAstNode* node) } } - FlushIndent(); + if (wantsPrefixSpace) + { + mQueuedSpaceCount++; + wantsPrefixSpace = false; + } + FlushIndent(); for (int idx = startIdx; idx <= BF_MIN(srcIdx, endIdx - 1); idx++) { @@ -1038,6 +1052,8 @@ void BfPrinter::Visit(BfLabelableStatement* labelableStmt) void BfPrinter::Visit(BfCommentNode* commentNode) { WriteIgnoredNode(commentNode); + if (commentNode->mCommentKind == BfCommentKind_Line) + ExpectNewLine(); } void BfPrinter::Visit(BfPreprocesorIgnoredSectionNode* preprocesorIgnoredSection) From f029419cea338617074fdc84a058b4f47b44aacd Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 21 Dec 2021 07:48:17 -0500 Subject: [PATCH 081/139] Option label change --- IDE/src/ui/SettingsDialog.bf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IDE/src/ui/SettingsDialog.bf b/IDE/src/ui/SettingsDialog.bf index f4f305b5..4ada4d19 100644 --- a/IDE/src/ui/SettingsDialog.bf +++ b/IDE/src/ui/SettingsDialog.bf @@ -126,7 +126,7 @@ namespace IDE.ui AddPropertiesItem(category, "Enable File Recovery", "mEnableFileRecovery"); AddPropertiesItem(category, "Format on Save", "mFormatOnSave"); AddPropertiesItem(category, "Sync with Workspace Panel", "mSyncWithWorkspacePanel"); - AddPropertiesItem(category, "Wrap comments at length (0 = none)", "mWrapCommentsAt"); + AddPropertiesItem(category, "Wrap Comments at Column", "mWrapCommentsAt"); category.Open(true, true); } From dc1a7f9cbb99106cb44fd70e52c2df482a641975 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 21 Dec 2021 07:49:40 -0500 Subject: [PATCH 082/139] Selection fix --- IDE/src/ui/SourceEditWidgetContent.bf | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/IDE/src/ui/SourceEditWidgetContent.bf b/IDE/src/ui/SourceEditWidgetContent.bf index 755484b5..8666bbe6 100644 --- a/IDE/src/ui/SourceEditWidgetContent.bf +++ b/IDE/src/ui/SourceEditWidgetContent.bf @@ -2318,6 +2318,7 @@ namespace IDE.ui if (CheckReadOnly()) return false; bool noStar = false; + var prevSelection = mSelection; var startLineAndCol = CursorLineAndColumn; if ((!HasSelection()) && (doComment != null)) @@ -2448,6 +2449,10 @@ namespace IDE.ui } mSelection = EditSelection(minPos, maxPos + q); } + else + { + mSelection = prevSelection; + } if (undoBatchStart != null) mData.mUndoManager.Add(undoBatchStart.mBatchEnd); From 27352386348d06605e07813677beb57f7bb1efa6 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 21 Dec 2021 07:49:57 -0500 Subject: [PATCH 083/139] Comment Selection name change --- IDE/src/Commands.bf | 2 +- IDE/src/IDEApp.bf | 4 ++-- IDE/src/Settings.bf | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/IDE/src/Commands.bf b/IDE/src/Commands.bf index c7eeb2cf..7883e4b2 100644 --- a/IDE/src/Commands.bf +++ b/IDE/src/Commands.bf @@ -196,7 +196,7 @@ namespace IDE Add("Close Workspace", new => gApp.[Friend]Cmd_CloseWorkspaceAndSetupNew); Add("Comment Block", new => gApp.[Friend]CommentBlock); Add("Comment Lines", new => gApp.[Friend]CommentLines); - Add("Comment Selection", new => gApp.[Friend]CommentSelection); + Add("Comment Toggle", new => gApp.[Friend]CommentToggle); Add("Compile File", new => gApp.Cmd_CompileFile); Add("Debug All Tests", new () => { gApp.[Friend]RunTests(true, true); }); Add("Debug Normal Tests", new () => { gApp.[Friend]RunTests(false, true); }); diff --git a/IDE/src/IDEApp.bf b/IDE/src/IDEApp.bf index 0c695e54..7d2391f8 100644 --- a/IDE/src/IDEApp.bf +++ b/IDE/src/IDEApp.bf @@ -2446,7 +2446,7 @@ namespace IDE } [IDECommand] - void CommentSelection() + void CommentToggle() { var sewc = GetActiveSourceEditWidgetContent(); if (sewc != null) @@ -5409,7 +5409,7 @@ namespace IDE AddMenuItem(advancedEditMenu, "Make Lowercase", "Make Lowercase"); AddMenuItem(advancedEditMenu, "Comment Block", "Comment Block"); AddMenuItem(advancedEditMenu, "Comment Lines", "Comment Lines"); - AddMenuItem(advancedEditMenu, "Comment Selection", "Comment Selection"); + AddMenuItem(advancedEditMenu, "Comment Toggle", "Comment Toggle"); AddMenuItem(advancedEditMenu, "Uncomment Selection", "Uncomment Selection"); AddMenuItem(advancedEditMenu, "Reformat Document", "Reformat Document"); mViewWhiteSpace.mMenu = AddMenuItem(advancedEditMenu, "View White Space", "View White Space", null, null, true, mViewWhiteSpace.Bool ? 1 : 0); diff --git a/IDE/src/Settings.bf b/IDE/src/Settings.bf index e81f8344..ba5e5d39 100644 --- a/IDE/src/Settings.bf +++ b/IDE/src/Settings.bf @@ -756,9 +756,8 @@ namespace IDE Add("Cancel Build", "Ctrl+Break"); Add("Close Document", "Ctrl+W"); Add("Compile File", "Ctrl+F7"); - Add("Comment Block", "Ctrl+K, Ctrl+B"); + Add("Comment Block", "Ctrl+K, Ctrl+C"); Add("Comment Lines", "Ctrl+K, Ctrl+L"); - Add("Comment Selection", "Ctrl+K, Ctrl+C"); Add("Duplicate Line", "Ctrl+D"); Add("Find Class", "Alt+Shift+L"); Add("Find in Document", "Ctrl+F"); From d4460f02360cbc7bf14a2345f39a5d309c20961d Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 21 Dec 2021 07:53:08 -0500 Subject: [PATCH 084/139] Comment Toggle fix --- IDE/src/IDEApp.bf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IDE/src/IDEApp.bf b/IDE/src/IDEApp.bf index 7d2391f8..c27fc710 100644 --- a/IDE/src/IDEApp.bf +++ b/IDE/src/IDEApp.bf @@ -2450,7 +2450,7 @@ namespace IDE { var sewc = GetActiveSourceEditWidgetContent(); if (sewc != null) - sewc.ToggleComment(true); + sewc.ToggleComment(); } [IDECommand] From d5642b6558a9574f44adfaafc6335d9824a27cd5 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 21 Dec 2021 08:29:15 -0500 Subject: [PATCH 085/139] Added safe mode toggle to Preferences menu --- BeefLibs/Beefy2D/src/sys/SysMenu.bf | 6 ++++++ BeefLibs/Beefy2D/src/widgets/IMenu.bf | 1 + BeefLibs/Beefy2D/src/widgets/Menu.bf | 5 +++++ IDE/src/Commands.bf | 1 + IDE/src/IDEApp.bf | 20 ++++++++++++++------ 5 files changed, 27 insertions(+), 6 deletions(-) diff --git a/BeefLibs/Beefy2D/src/sys/SysMenu.bf b/BeefLibs/Beefy2D/src/sys/SysMenu.bf index 4dc7cda1..a125a554 100644 --- a/BeefLibs/Beefy2D/src/sys/SysMenu.bf +++ b/BeefLibs/Beefy2D/src/sys/SysMenu.bf @@ -69,6 +69,12 @@ namespace Beefy.sys Modify(mText, mHotKey, mBitmap, mEnabled, mCheckState, mRadioCheck); } + public void SetCheckState(int32 checkState) + { + mCheckState = checkState; + Modify(mText, mHotKey, mBitmap, mEnabled, mCheckState, mRadioCheck); + } + public void SetHotKey(StringView hotKey) { if (hotKey.IsNull) diff --git a/BeefLibs/Beefy2D/src/widgets/IMenu.bf b/BeefLibs/Beefy2D/src/widgets/IMenu.bf index a2174048..5156ffbf 100644 --- a/BeefLibs/Beefy2D/src/widgets/IMenu.bf +++ b/BeefLibs/Beefy2D/src/widgets/IMenu.bf @@ -10,6 +10,7 @@ namespace Beefy.widgets public interface IMenu { void SetDisabled(bool enable); + void SetCheckState(int32 checkState); } public interface IMenuContainer diff --git a/BeefLibs/Beefy2D/src/widgets/Menu.bf b/BeefLibs/Beefy2D/src/widgets/Menu.bf index dd6adfc5..2cfdf1dc 100644 --- a/BeefLibs/Beefy2D/src/widgets/Menu.bf +++ b/BeefLibs/Beefy2D/src/widgets/Menu.bf @@ -616,5 +616,10 @@ namespace Beefy.widgets { mDisabled = disabled; } + + public void SetCheckState(int32 checkState) + { + + } } } diff --git a/IDE/src/Commands.bf b/IDE/src/Commands.bf index 7883e4b2..3ba093c2 100644 --- a/IDE/src/Commands.bf +++ b/IDE/src/Commands.bf @@ -253,6 +253,7 @@ namespace IDE Add("Run Normal Tests", new () => { gApp.[Friend]RunTests(false, false); }); Add("Run To Cursor", new => gApp.[Friend]RunToCursor); Add("Run Without Compiling", new => gApp.[Friend]RunWithoutCompiling); + Add("Safe Mode Toggle", new () => { gApp.SafeModeToggle(); }); Add("Save All", new () => { gApp.SaveAll(); }); Add("Save As", new () => { gApp.SaveAs(); }); Add("Save File", new => gApp.SaveFile); diff --git a/IDE/src/IDEApp.bf b/IDE/src/IDEApp.bf index c27fc710..ac1dcbf4 100644 --- a/IDE/src/IDEApp.bf +++ b/IDE/src/IDEApp.bf @@ -4895,6 +4895,14 @@ namespace IDE CreateDefaultLayout(false); } + [IDECommand] + public void SafeModeToggle() + { + mSafeMode = !mSafeMode; + mNoResolve = mSafeMode; + mWantsBeefClean = true; + } + [IDECommand] public void ShowKeyboardShortcuts() { @@ -5331,6 +5339,7 @@ namespace IDE AddMenuItem(prefMenu, "&Settings", "Settings"); AddMenuItem(prefMenu, "Reload Settings", "Reload Settings"); AddMenuItem(prefMenu, "Reset UI", "Reset UI"); + AddMenuItem(prefMenu, "Safe Mode", "Safe Mode Toggle", new (menu) => { menu.SetCheckState(mSafeMode ? 1 : 0); }, null, true, mSafeMode ? 1 : 0); AddMenuItem(subMenu, "Close Workspace", "Close Workspace", new => UpdateMenuItem_HasWorkspace); AddMenuItem(subMenu, "E&xit", "Exit"); @@ -12078,11 +12087,11 @@ namespace IDE if (mErrorsPanel != null) mErrorsPanel.ClearParserErrors(null); - delete mBfResolveCompiler; - delete mBfResolveSystem; - delete mBfResolveHelper; - delete mBfBuildCompiler; - delete mBfBuildSystem; + DeleteAndNullify!(mBfResolveCompiler); + DeleteAndNullify!(mBfResolveSystem); + DeleteAndNullify!(mBfResolveHelper); + DeleteAndNullify!(mBfBuildCompiler); + DeleteAndNullify!(mBfBuildSystem); /// mDebugger.FullReportMemory(); @@ -13736,7 +13745,6 @@ namespace IDE [Import("user32.lib"), CLink, CallingConvention(.Stdcall)] public static extern bool MessageBeep(MessageBeepType type); #endif - } static From 8807c1ea83a8f7ef85a4eee906544668de603353 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 21 Dec 2021 08:58:37 -0500 Subject: [PATCH 086/139] Break When Value Changes fix for `*` deref exprs --- IDE/src/ui/WatchPanel.bf | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/IDE/src/ui/WatchPanel.bf b/IDE/src/ui/WatchPanel.bf index 06da55be..8779e76d 100644 --- a/IDE/src/ui/WatchPanel.bf +++ b/IDE/src/ui/WatchPanel.bf @@ -2765,7 +2765,10 @@ namespace IDE.ui { String evalStr = scope String(); CompactChildExpression(listViewItem, evalStr); - evalStr.Insert(0, "&"); + if (evalStr.StartsWith("*")) + evalStr.Remove(0, 1); + else + evalStr.Insert(0, "&"); gApp.mBreakpointPanel.CreateMemoryBreakpoint(evalStr); gApp.MarkDirty(); }); From 326c33eaa147704a38f32819e4cab12ce8a0b63d Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 21 Dec 2021 12:52:51 -0500 Subject: [PATCH 087/139] Predetermine enum discriminator during comptime --- IDEHelper/Compiler/BfModule.h | 10 +- IDEHelper/Compiler/BfModuleTypeUtils.cpp | 338 ++++++++++++----------- IDEHelper/Compiler/CeMachine.cpp | 7 + IDEHelper/Tests/src/Comptime.bf | 32 +++ 4 files changed, 228 insertions(+), 159 deletions(-) diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index efa5ae8f..d575d265 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -1744,13 +1744,15 @@ public: void FinishCEParseContext(BfAstNode* refNode, BfTypeInstance* typeInstance, BfCEParseContext* ceParseContext); BfCEParseContext CEEmitParse(BfTypeInstance* typeInstance, const StringImpl& src); void UpdateCEEmit(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance, const StringImpl& ctxString, BfAstNode* refNode); - void HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance* typeInst, BfCustomAttributes* customAttributes, HashSet foundAttributes); + void HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance* typeInst, BfCustomAttributes* customAttributes, HashSet foundAttributes, bool underlyingTypeDeferred); void CEMixin(BfAstNode* refNode, const StringImpl& src); - void ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance* typeInst, BfCEOnCompileKind onCompileKind); - void DoCEEmit(BfTypeInstance* typeInstance, bool& hadNewMembers); + void ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance* typeInst, BfCEOnCompileKind onCompileKind, bool underlyingTypeDeferred); + void DoCEEmit(BfTypeInstance* typeInstance, bool& hadNewMembers, bool underlyingTypeDeferred); void DoCEEmit(BfMethodInstance* methodInstance); void DoPopulateType_TypeAlias(BfTypeInstance* typeAlias); - void DoPopulateType_SetGenericDependencies(BfTypeInstance* genericTypeInstance); + void DoPopulateType_SetGenericDependencies(BfTypeInstance* genericTypeInstance); + void DoPopulateType_FinishEnum(BfTypeInstance* typeInstance, bool underlyingTypeDeferred, HashContext* dataMemberHashCtx, BfType* unionInnerType); + void DoPopulateType_CeCheckEnum(BfTypeInstance* typeInstance, bool underlyingTypeDeferred); void DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateType = BfPopulateType_Data); static BfModule* GetModuleFor(BfType* type); void DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance); diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 73b8459f..7a93ce43 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -2136,7 +2136,7 @@ void BfModule::UpdateCEEmit(CeEmitContext* ceEmitContext, BfTypeInstance* typeIn } } -void BfModule::HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance, BfCustomAttributes* customAttributes, HashSet foundAttributes) +void BfModule::HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance, BfCustomAttributes* customAttributes, HashSet foundAttributes, bool underlyingTypeDeferred) { BfTypeInstance* iComptimeTypeApply = NULL; for (auto& customAttribute : customAttributes->mAttributes) @@ -2170,6 +2170,7 @@ void BfModule::HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance* args.Add(attrVal); args.Add(mBfIRBuilder->CreateTypeOf(typeInstance)); + DoPopulateType_CeCheckEnum(typeInstance, underlyingTypeDeferred); auto result = ceContext->Call(customAttribute.mRef, this, methodInstance, args, CeEvalFlags_None, NULL); if (typeInstance->mDefineState == BfTypeDefineState_DefinedAndMethodsSlotted) @@ -2300,18 +2301,18 @@ void BfModule::CEMixin(BfAstNode* refNode, const StringImpl& code) FinishCEParseContext(refNode, mCurTypeInstance, &ceParseContext); } -void BfModule::ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance, BfCEOnCompileKind onCompileKind) +void BfModule::ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance, BfCEOnCompileKind onCompileKind, bool underlyingTypeDeferred) { HashSet foundAttributes; if (ceEmitContext != NULL) { if (typeInstance->mCustomAttributes != NULL) - HandleCEAttributes(ceEmitContext, typeInstance, typeInstance->mCustomAttributes, foundAttributes); + HandleCEAttributes(ceEmitContext, typeInstance, typeInstance->mCustomAttributes, foundAttributes, underlyingTypeDeferred); for (auto& fieldInstance : typeInstance->mFieldInstances) { if (fieldInstance.mCustomAttributes != NULL) - HandleCEAttributes(ceEmitContext, typeInstance, fieldInstance.mCustomAttributes, foundAttributes); + HandleCEAttributes(ceEmitContext, typeInstance, fieldInstance.mCustomAttributes, foundAttributes, underlyingTypeDeferred); } } @@ -2353,7 +2354,7 @@ void BfModule::ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance* if (onCompileAttribute == NULL) continue; - HandleCEAttributes(ceEmitContext, typeInstance, customAttributes, foundAttributes); + HandleCEAttributes(ceEmitContext, typeInstance, customAttributes, foundAttributes, underlyingTypeDeferred); if (onCompileAttribute->mCtorArgs.size() < 1) continue; @@ -2381,6 +2382,7 @@ void BfModule::ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance* mCompiler->mCEMachine->mCurEmitContext = ceEmitContext; } + DoPopulateType_CeCheckEnum(typeInstance, underlyingTypeDeferred); auto methodInstance = GetRawMethodInstanceAtIdx(typeInstance, methodDef->mIdx); auto result = mCompiler->mCEMachine->Call(methodDef->GetRefNode(), this, methodInstance, {}, (CeEvalFlags)(CeEvalFlags_PersistantError | CeEvalFlags_DeferIfNotOnlyError), NULL); @@ -2449,11 +2451,11 @@ void BfModule::ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance* // } } -void BfModule::DoCEEmit(BfTypeInstance* typeInstance, bool& hadNewMembers) +void BfModule::DoCEEmit(BfTypeInstance* typeInstance, bool& hadNewMembers, bool underlyingTypeDeferred) { CeEmitContext ceEmitContext; ceEmitContext.mType = typeInstance; - ExecuteCEOnCompile(&ceEmitContext, typeInstance, BfCEOnCompileKind_TypeInit); + ExecuteCEOnCompile(&ceEmitContext, typeInstance, BfCEOnCompileKind_TypeInit, underlyingTypeDeferred); hadNewMembers = (typeInstance->mTypeDef->mEmitParent != NULL); if (ceEmitContext.mFailed) @@ -2607,7 +2609,7 @@ void BfModule::DoPopulateType_SetGenericDependencies(BfTypeInstance* genericType } void BfModule::DoPopulateType_TypeAlias(BfTypeInstance* typeAlias) -{ +{ SetAndRestoreValue prevTypeInstance(mCurTypeInstance, typeAlias); SetAndRestoreValue prevMethodInstance(mCurMethodInstance, NULL); SetAndRestoreValue prevMethodState(mCurMethodState, NULL); @@ -2683,6 +2685,176 @@ void BfModule::DoPopulateType_TypeAlias(BfTypeInstance* typeAlias) DoPopulateType_SetGenericDependencies(typeAlias); } +void BfModule::DoPopulateType_FinishEnum(BfTypeInstance* typeInstance, bool underlyingTypeDeferred, HashContext* dataMemberHashCtx, BfType* unionInnerType) +{ + if (typeInstance->IsEnum()) + { + int64 min = 0; + int64 max = 0; + + bool isFirst = true; + + if (typeInstance->mTypeInfoEx == NULL) + typeInstance->mTypeInfoEx = new BfTypeInfoEx(); + + for (auto& fieldInstanceRef : typeInstance->mFieldInstances) + { + auto fieldInstance = &fieldInstanceRef; + auto fieldDef = fieldInstance->GetFieldDef(); + if ((fieldDef != NULL) && (fieldDef->IsEnumCaseEntry())) + { + if (fieldInstance->mConstIdx == -1) + continue; + + auto constant = typeInstance->mConstHolder->GetConstantById(fieldInstance->mConstIdx); + BF_ASSERT((constant->mTypeCode == BfTypeCode_Int64) || (!underlyingTypeDeferred)); + + if (isFirst) + { + min = constant->mInt64; + max = constant->mInt64; + isFirst = false; + } + else + { + min = BF_MIN(constant->mInt64, min); + max = BF_MAX(constant->mInt64, max); + } + } + } + + typeInstance->mTypeInfoEx->mMinValue = min; + typeInstance->mTypeInfoEx->mMaxValue = max; + + if (underlyingTypeDeferred) + { + BfTypeCode typeCode; + + if ((min >= -0x80) && (max <= 0x7F)) + typeCode = BfTypeCode_Int8; + else if ((min >= 0) && (max <= 0xFF)) + typeCode = BfTypeCode_UInt8; + else if ((min >= -0x8000) && (max <= 0x7FFF)) + typeCode = BfTypeCode_Int16; + else if ((min >= 0) && (max <= 0xFFFF)) + typeCode = BfTypeCode_UInt16; + else if ((min >= -0x80000000LL) && (max <= 0x7FFFFFFF)) + typeCode = BfTypeCode_Int32; + else if ((min >= 0) && (max <= 0xFFFFFFFFLL)) + typeCode = BfTypeCode_UInt32; + else + typeCode = BfTypeCode_Int64; + + if (typeCode != BfTypeCode_Int64) + { + for (auto& fieldInstanceRef : typeInstance->mFieldInstances) + { + auto fieldInstance = &fieldInstanceRef; + if (fieldInstance->mConstIdx == -1) + continue; + if (!fieldInstance->GetFieldDef()->IsEnumCaseEntry()) + continue; + auto constant = typeInstance->mConstHolder->GetConstantById(fieldInstance->mConstIdx); + BfIRValue newConstant = typeInstance->mConstHolder->CreateConst(typeCode, constant->mUInt64); + fieldInstance->mConstIdx = newConstant.mId; + } + } + + BfType* underlyingType = GetPrimitiveType(typeCode); + auto fieldInstance = &typeInstance->mFieldInstances.back(); + fieldInstance->mResolvedType = underlyingType; + fieldInstance->mDataSize = underlyingType->mSize; + + typeInstance->mTypeInfoEx->mUnderlyingType = underlyingType; + + typeInstance->mSize = underlyingType->mSize; + typeInstance->mAlign = underlyingType->mAlign; + typeInstance->mInstSize = underlyingType->mSize; + typeInstance->mInstAlign = underlyingType->mAlign; + + typeInstance->mRebuildFlags = (BfTypeRebuildFlags)(typeInstance->mRebuildFlags & ~BfTypeRebuildFlag_UnderlyingTypeDeferred); + } + } + else + { + BF_ASSERT(!underlyingTypeDeferred); + } + + if ((typeInstance->IsPayloadEnum()) && (!typeInstance->IsBoxed())) + { + typeInstance->mAlign = unionInnerType->mAlign; + + int lastTagId = -1; + for (auto& fieldInstanceRef : typeInstance->mFieldInstances) + { + auto fieldInstance = &fieldInstanceRef; + auto fieldDef = fieldInstance->GetFieldDef(); + if ((fieldDef != NULL) && (fieldInstance->mDataIdx < 0)) + { + BF_ASSERT(fieldInstance->mResolvedType->mAlign >= 1); + typeInstance->mAlign = BF_MAX(typeInstance->mAlign, fieldInstance->mResolvedType->mAlign); + lastTagId = -fieldInstance->mDataIdx - 1; + } + } + + auto fieldInstance = &typeInstance->mFieldInstances.back(); + //BF_ASSERT(fieldInstance->mResolvedType == NULL); + BfPrimitiveType* discriminatorType; + if (lastTagId > 0x7FFFFFFF) // HOW? + discriminatorType = GetPrimitiveType(BfTypeCode_Int64); + else if (lastTagId > 0x7FFF) + discriminatorType = GetPrimitiveType(BfTypeCode_Int32); + else if (lastTagId > 0x7F) + discriminatorType = GetPrimitiveType(BfTypeCode_Int16); + else + discriminatorType = GetPrimitiveType(BfTypeCode_Int8); + fieldInstance->mResolvedType = discriminatorType; + + fieldInstance->mDataOffset = unionInnerType->mSize; + fieldInstance->mDataIdx = 2; // 0 = base, 1 = payload, 2 = discriminator + if (!typeInstance->mIsPacked) + { + if ((fieldInstance->mDataOffset % discriminatorType->mAlign) != 0) + { + fieldInstance->mDataOffset = BF_ALIGN(fieldInstance->mDataOffset, discriminatorType->mAlign); + fieldInstance->mDataIdx++; // Add room for explicit padding + } + } + + typeInstance->mAlign = BF_MAX(typeInstance->mAlign, discriminatorType->mAlign); + typeInstance->mSize = fieldInstance->mDataOffset + discriminatorType->mSize; + + typeInstance->mInstSize = typeInstance->mSize; + typeInstance->mInstAlign = typeInstance->mAlign; + + if (dataMemberHashCtx != NULL) + { + dataMemberHashCtx->Mixin(unionInnerType->mTypeId); + dataMemberHashCtx->Mixin(discriminatorType->mTypeId); + } + + typeInstance->mMergedFieldDataCount = 1; // Track it as a single entry + } +} + +void BfModule::DoPopulateType_CeCheckEnum(BfTypeInstance* typeInstance, bool underlyingTypeDeferred) +{ + if (!typeInstance->IsEnum()) + return; + if ((!underlyingTypeDeferred) && (!typeInstance->IsPayloadEnum())) + return; + if ((typeInstance->mCeTypeInfo != NULL) && (typeInstance->mCeTypeInfo->mNext != NULL)) + return; + + BfType* unionInnerType = NULL; + if (typeInstance->mIsUnion) + { + SetAndRestoreValue prevResolveKind(mContext->mCurTypeState->mResolveKind, BfTypeState::ResolveKind_UnionInnerType); + unionInnerType = typeInstance->GetUnionInnerType(); + } + DoPopulateType_FinishEnum(typeInstance, underlyingTypeDeferred, NULL, unionInnerType); +} + void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateType) { if (populateType == BfPopulateType_Identity) @@ -4055,7 +4227,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy typeInstance->mDefineState = BfTypeDefineState_CETypeInit; bool hadNewMembers = false; - DoCEEmit(typeInstance, hadNewMembers); + DoCEEmit(typeInstance, hadNewMembers, underlyingTypeDeferred); if (typeInstance->mDefineState < BfTypeDefineState_CEPostTypeInit) typeInstance->mDefineState = BfTypeDefineState_CEPostTypeInit; @@ -4659,7 +4831,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy typeInstance->mDefineState = BfTypeDefineState_Defined; if (!typeInstance->IsBoxed()) { - ExecuteCEOnCompile(NULL, typeInstance, BfCEOnCompileKind_TypeDone); + ExecuteCEOnCompile(NULL, typeInstance, BfCEOnCompileKind_TypeDone, underlyingTypeDeferred); if (typeInstance->mDefineState == BfTypeDefineState_DefinedAndMethodsSlotted) return; } @@ -4830,151 +5002,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy BfLogSysM("Setting underlying type %p %d\n", typeInstance, underlyingTypeDeferred); } - if (typeInstance->IsEnum()) - { - int64 min = 0; - int64 max = 0; - - bool isFirst = true; - - if (typeInstance->mTypeInfoEx == NULL) - typeInstance->mTypeInfoEx = new BfTypeInfoEx(); - - for (auto& fieldInstanceRef : typeInstance->mFieldInstances) - { - auto fieldInstance = &fieldInstanceRef; - auto fieldDef = fieldInstance->GetFieldDef(); - if ((fieldDef != NULL) && (fieldDef->IsEnumCaseEntry())) - { - if (fieldInstance->mConstIdx == -1) - continue; - - auto constant = typeInstance->mConstHolder->GetConstantById(fieldInstance->mConstIdx); - BF_ASSERT((constant->mTypeCode == BfTypeCode_Int64) || (!underlyingTypeDeferred)); - - if (isFirst) - { - min = constant->mInt64; - max = constant->mInt64; - isFirst = false; - } - else - { - min = BF_MIN(constant->mInt64, min); - max = BF_MAX(constant->mInt64, max); - } - } - } - - typeInstance->mTypeInfoEx->mMinValue = min; - typeInstance->mTypeInfoEx->mMaxValue = max; - - if (underlyingTypeDeferred) - { - BfTypeCode typeCode; - - if ((min >= -0x80) && (max <= 0x7F)) - typeCode = BfTypeCode_Int8; - else if ((min >= 0) && (max <= 0xFF)) - typeCode = BfTypeCode_UInt8; - else if ((min >= -0x8000) && (max <= 0x7FFF)) - typeCode = BfTypeCode_Int16; - else if ((min >= 0) && (max <= 0xFFFF)) - typeCode = BfTypeCode_UInt16; - else if ((min >= -0x80000000LL) && (max <= 0x7FFFFFFF)) - typeCode = BfTypeCode_Int32; - else if ((min >= 0) && (max <= 0xFFFFFFFFLL)) - typeCode = BfTypeCode_UInt32; - else - typeCode = BfTypeCode_Int64; - - if (typeCode != BfTypeCode_Int64) - { - for (auto& fieldInstanceRef : typeInstance->mFieldInstances) - { - auto fieldInstance = &fieldInstanceRef; - if (fieldInstance->mConstIdx == -1) - continue; - if (!fieldInstance->GetFieldDef()->IsEnumCaseEntry()) - continue; - auto constant = typeInstance->mConstHolder->GetConstantById(fieldInstance->mConstIdx); - BfIRValue newConstant = typeInstance->mConstHolder->CreateConst(typeCode, constant->mUInt64); - fieldInstance->mConstIdx = newConstant.mId; - } - } - - underlyingType = GetPrimitiveType(typeCode); - auto fieldInstance = &typeInstance->mFieldInstances.back(); - fieldInstance->mResolvedType = underlyingType; - fieldInstance->mDataSize = underlyingType->mSize; - - typeInstance->mTypeInfoEx->mUnderlyingType = underlyingType; - - typeInstance->mSize = underlyingType->mSize; - typeInstance->mAlign = underlyingType->mAlign; - typeInstance->mInstSize = underlyingType->mSize; - typeInstance->mInstAlign = underlyingType->mAlign; - - typeInstance->mRebuildFlags = (BfTypeRebuildFlags)(typeInstance->mRebuildFlags & ~BfTypeRebuildFlag_UnderlyingTypeDeferred); - } - } - else - { - BF_ASSERT(!underlyingTypeDeferred); - } - - if ((typeInstance->IsPayloadEnum()) && (!typeInstance->IsBoxed())) - { - typeInstance->mAlign = unionInnerType->mAlign; - - int lastTagId = -1; - for (auto& fieldInstanceRef : typeInstance->mFieldInstances) - { - auto fieldInstance = &fieldInstanceRef; - auto fieldDef = fieldInstance->GetFieldDef(); - if ((fieldDef != NULL) && (fieldInstance->mDataIdx < 0)) - { - BF_ASSERT(fieldInstance->mResolvedType->mAlign >= 1); - typeInstance->mAlign = BF_MAX(typeInstance->mAlign, fieldInstance->mResolvedType->mAlign); - lastTagId = -fieldInstance->mDataIdx - 1; - } - } - - auto fieldInstance = &typeInstance->mFieldInstances.back(); - BF_ASSERT(fieldInstance->mResolvedType == NULL); - BfPrimitiveType* discriminatorType; - if (lastTagId > 0x7FFFFFFF) // HOW? - discriminatorType = GetPrimitiveType(BfTypeCode_Int64); - else if (lastTagId > 0x7FFF) - discriminatorType = GetPrimitiveType(BfTypeCode_Int32); - else if (lastTagId > 0x7F) - discriminatorType = GetPrimitiveType(BfTypeCode_Int16); - else - discriminatorType = GetPrimitiveType(BfTypeCode_Int8); - fieldInstance->mResolvedType = discriminatorType; - - fieldInstance->mDataOffset = unionInnerType->mSize; - fieldInstance->mDataIdx = 2; // 0 = base, 1 = payload, 2 = discriminator - if (!isPacked) - { - if ((fieldInstance->mDataOffset % discriminatorType->mAlign) != 0) - { - fieldInstance->mDataOffset = BF_ALIGN(fieldInstance->mDataOffset, discriminatorType->mAlign); - fieldInstance->mDataIdx++; // Add room for explicit padding - } - } - - typeInstance->mAlign = BF_MAX(typeInstance->mAlign, discriminatorType->mAlign); - typeInstance->mSize = fieldInstance->mDataOffset + discriminatorType->mSize; - - typeInstance->mInstSize = typeInstance->mSize; - typeInstance->mInstAlign = typeInstance->mAlign; - - dataMemberHashCtx.Mixin(unionInnerType->mTypeId); - dataMemberHashCtx.Mixin(discriminatorType->mTypeId); - - typeInstance->mMergedFieldDataCount = 1; // Track it as a single entry - } + DoPopulateType_FinishEnum(typeInstance, underlyingTypeDeferred, &dataMemberHashCtx, unionInnerType); if (!typeInstance->IsBoxed()) { diff --git a/IDEHelper/Compiler/CeMachine.cpp b/IDEHelper/Compiler/CeMachine.cpp index 8517ad00..7b1ac835 100644 --- a/IDEHelper/Compiler/CeMachine.cpp +++ b/IDEHelper/Compiler/CeMachine.cpp @@ -6081,6 +6081,13 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* { if (iface.mInterfaceType == ifaceType) { + if (valueType->mInterfaceMethodTable.IsEmpty()) + ceModule->PopulateType(valueType, BfPopulateType_Full_Force); + if (valueType->mInterfaceMethodTable.IsEmpty()) + { + _Fail("Empty interface table"); + return false; + } methodInstance = valueType->mInterfaceMethodTable[iface.mStartInterfaceTableIdx + methodIdx].mMethodRef; break; } diff --git a/IDEHelper/Tests/src/Comptime.bf b/IDEHelper/Tests/src/Comptime.bf index 7434fe8f..09831d41 100644 --- a/IDEHelper/Tests/src/Comptime.bf +++ b/IDEHelper/Tests/src/Comptime.bf @@ -230,6 +230,38 @@ namespace Tests } } + [CheckEnum] + enum EnumA + { + case A(int64 aa); + case B(float bb); + } + + [AttributeUsage(.All)] + public struct CheckEnumAttribute : Attribute, IComptimeTypeApply + { + public void ApplyToType(Type type) + { + int fieldIdx = 0; + for (var field in type.GetFields()) + { + switch (fieldIdx) + { + case 0: + Test.Assert(field.Name == "$payload"); + Test.Assert(field.MemberOffset == 0); + Test.Assert(field.FieldType == typeof(int64)); + case 1: + Test.Assert(field.Name == "$discriminator"); + Test.Assert(field.MemberOffset == 8); + Test.Assert(field.FieldType == typeof(int8)); + } + fieldIdx++; + } + Test.Assert(fieldIdx == 4); + } + } + const String cTest0 = Compiler.ReadText("Test0.txt"); const String cTest1 = new String('A', 12); const uint8[?] cTest0Binary = Compiler.ReadBinary("Test0.txt"); From 74a63f7561f253ccb66f6e8f0320e576671b7d8c Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 21 Dec 2021 13:07:30 -0500 Subject: [PATCH 088/139] TLS setup reg selection fix --- IDEHelper/Backend/BeMCContext.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/IDEHelper/Backend/BeMCContext.cpp b/IDEHelper/Backend/BeMCContext.cpp index 1112dca9..77dbb095 100644 --- a/IDEHelper/Backend/BeMCContext.cpp +++ b/IDEHelper/Backend/BeMCContext.cpp @@ -2171,6 +2171,8 @@ BeMCOperand BeMCContext::GetOperand(BeValue* value, bool allowMetaResult, bool a auto vregInfo = GetVRegInfo(tlsVReg); vregInfo->mMustExist = true; vregInfo->mForceReg = true; + vregInfo->mDisableR12 = true; + vregInfo->mDisableR13 = true; mTLSVRegIdx = tlsVReg.mVRegIdx; } @@ -15930,7 +15932,7 @@ void BeMCContext::Generate(BeFunction* function) mDbgPreferredRegs[32] = X64Reg_R8;*/ //mDbgPreferredRegs[8] = X64Reg_RAX; - //mDebugging = (function->mName == "?Load@TestProgram@BeefTest@bf@@SA?AUHandle@23@XZ"); + //mDebugging = (function->mName == "?InitThread@Foo@BeefTest@bf@@CA?AU?$Result@X@System@3@H@Z"); // || (function->mName == "?MethodA@TestProgram@BeefTest@bf@@CAXXZ"); // || (function->mName == "?Hey@Blurg@bf@@SAXXZ") // ; From 4c421033ab3f6a17fd3b9d511140cdad6e022eec Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 21 Dec 2021 14:46:29 -0500 Subject: [PATCH 089/139] Comment tweaks `//` is placed at the column where text starts on the first line Toggle comment can insert a line comment with no selection Selection state is retained Undo restores selection and cursor position --- IDE/src/ui/SourceEditWidgetContent.bf | 217 +++++++++++++++----------- 1 file changed, 124 insertions(+), 93 deletions(-) diff --git a/IDE/src/ui/SourceEditWidgetContent.bf b/IDE/src/ui/SourceEditWidgetContent.bf index 8666bbe6..edbdb723 100644 --- a/IDE/src/ui/SourceEditWidgetContent.bf +++ b/IDE/src/ui/SourceEditWidgetContent.bf @@ -2167,6 +2167,11 @@ namespace IDE.ui if (CheckReadOnly()) return false; + var startLineAndCol = CursorLineAndColumn; + int startTextPos = CursorTextPos; + var prevSelection = mSelection; + bool hadSelection = HasSelection(); + if ((!HasSelection()) && (doComment != null)) { CursorToLineEnd(); @@ -2177,12 +2182,13 @@ namespace IDE.ui if ((HasSelection()) && (mSelection.Value.Length > 1)) { - var startLineAndCol = CursorLineAndColumn; - UndoBatchStart undoBatchStart = new UndoBatchStart("embeddedCommentBlock"); mData.mUndoManager.Add(undoBatchStart); - mData.mUndoManager.Add(new SetCursorAction(this)); + var setCursorAction = new SetCursorAction(this); + setCursorAction.mSelection = prevSelection; + setCursorAction.mCursorTextPos = (.)startTextPos; + mData.mUndoManager.Add(setCursorAction); int minPos = mSelection.GetValueOrDefault().MinPos; int maxPos = mSelection.GetValueOrDefault().MaxPos; @@ -2216,9 +2222,12 @@ namespace IDE.ui if (undoBatchStart != null) mData.mUndoManager.Add(undoBatchStart.mBatchEnd); - CursorLineAndColumn = startLineAndCol; + if (startTextPos <= minPos) + CursorLineAndColumn = startLineAndCol; + else if (startTextPos < maxPos) + CursorTextPos = startTextPos + 2; - if (doComment == null) + if ((doComment == null) || (!hadSelection)) mSelection = null; return true; @@ -2229,120 +2238,142 @@ namespace IDE.ui public bool CommentLines() { - bool? doComment = true; if (CheckReadOnly()) return false; - bool noStar = false; + int startTextPos = CursorTextPos; + var prevSelection = mSelection; + bool hadSelection = HasSelection(); var startLineAndCol = CursorLineAndColumn; - if ((!HasSelection()) && (doComment != null)) + if (!HasSelection()) { CursorToLineEnd(); int cursorEndPos = CursorTextPos; - + CursorToLineStart(false); mSelection = .(CursorTextPos, cursorEndPos); - noStar = true; } - if (true || (HasSelection()) && (mSelection.Value.Length > 0)) + UndoBatchStart undoBatchStart = new UndoBatchStart("embeddedCommentLines"); + mData.mUndoManager.Add(undoBatchStart); + + var setCursorAction = new SetCursorAction(this); + setCursorAction.mSelection = prevSelection; + setCursorAction.mCursorTextPos = (.)startTextPos; + mData.mUndoManager.Add(setCursorAction); + + int minPos = mSelection.GetValueOrDefault().MinPos; + int maxPos = mSelection.GetValueOrDefault().MaxPos; + mSelection = null; + + while (minPos >= 0) { - // set selection to begin from line start - int lineIdx; - int lineChar; - GetLineCharAtIdx(mSelection.GetValueOrDefault().MinPos,out lineIdx, out lineChar); - MoveCursorTo(lineIdx, 0); - mSelection = .(CursorTextPos, mSelection.GetValueOrDefault().MaxPos); + var c = mData.mText[minPos - 1].mChar; + if (c == '\n') + break; + minPos--; + } + + int wantLineCol = -1; + int lineStartCol = 0; + bool didLineComment = false; - UndoBatchStart undoBatchStart = new UndoBatchStart("embeddedCommentLines"); - mData.mUndoManager.Add(undoBatchStart); - - mData.mUndoManager.Add(new SetCursorAction(this)); - - int minPos = mSelection.GetValueOrDefault().MinPos; - int maxPos = mSelection.GetValueOrDefault().MaxPos; - mSelection = null; - - var str = scope String(); - ExtractString(minPos, maxPos - minPos, str); - var trimmedStr = scope String(); - trimmedStr.Append(str); - int32 startLen = (int32)trimmedStr.Length; - trimmedStr.TrimStart(); - int32 afterTrimStart = (int32)trimmedStr.Length; - trimmedStr.TrimEnd(); - //int32 afterTrimEnd = (int32)trimmedStr.Length; - trimmedStr.Append('\n'); - - int firstCharPos = minPos + (startLen - afterTrimStart); - //int lastCharPos = maxPos - (afterTrimStart - afterTrimEnd); - - int q = 0; - - if (doComment != false) + for (int i = minPos; i < maxPos; i++) + { + bool isSpace = false; + var c = mData.mText[i].mChar; + if (didLineComment) { - while (firstCharPos >= 0 && SafeGetChar(firstCharPos) != '\n') + if (c == '\n') { - firstCharPos--; + didLineComment = false; + lineStartCol = 0; } - bool blank=true; - for (int i = firstCharPos + 1; i < maxPos + q; i++) - { - blank=false; - CursorTextPos = i; // needed to add i < maxPos + q; for this to work with InsertAtCursor - InsertAtCursor("//"); q++; q++; - - while (SafeGetChar(i) != '\n' && i < maxPos + q) - { - i++; - } - } - mSelection = EditSelection(minPos, maxPos + q); + continue; } - if (undoBatchStart != null) - mData.mUndoManager.Add(undoBatchStart.mBatchEnd); + bool commentNow = false; + if ((wantLineCol != -1) && (lineStartCol >= wantLineCol)) + commentNow = true; - CursorLineAndColumn = startLineAndCol; + if (c == '\t') + { + lineStartCol += 4; + isSpace = true; + } + else if (c == ' ') + { + lineStartCol++; + isSpace = true; + } - if (doComment == null) - mSelection = null; + if (!isSpace) + { + if (c == '\n') + { + + } - return true; + commentNow = true; + if (wantLineCol == -1) + wantLineCol = lineStartCol; + } + + if (commentNow) + { + CursorTextPos = i; + String str = scope .(); + while (lineStartCol + 4 <= wantLineCol) + { + lineStartCol += 4; + str.Append("\t"); + } + str.Append("//"); + InsertAtCursor(str); + didLineComment = true; + maxPos += str.Length; + } } + mSelection = EditSelection(minPos, maxPos); - //return false; + if (undoBatchStart != null) + mData.mUndoManager.Add(undoBatchStart.mBatchEnd); + + CursorLineAndColumn = startLineAndCol; + + if (!hadSelection) + mSelection = null; + + return true; } public bool ToggleComment(bool? doComment = null) { if (CheckReadOnly()) return false; - bool noStar = false; + + int startTextPos = CursorTextPos; + bool doLineComment = false; var prevSelection = mSelection; - var startLineAndCol = CursorLineAndColumn; - if ((!HasSelection()) && (doComment != null)) + LineAndColumn? startLineAndCol = CursorLineAndColumn; + if (!HasSelection()) { CursorToLineEnd(); int cursorEndPos = CursorTextPos; CursorToLineStart(false); mSelection = .(CursorTextPos, cursorEndPos); - noStar = true; + doLineComment = true; } if ((HasSelection()) && (mSelection.Value.Length > 0)) { - int lineIdx; - int lineChar; - GetLineCharAtIdx(mSelection.GetValueOrDefault().MinPos, out lineIdx, out lineChar); - MoveCursorTo(lineIdx, 0); - mSelection = .(CursorTextPos, mSelection.GetValueOrDefault().MaxPos); - - UndoBatchStart undoBatchStart = new UndoBatchStart("embeddedToggleComment"); mData.mUndoManager.Add(undoBatchStart); - mData.mUndoManager.Add(new SetCursorAction(this)); + var setCursorAction = new SetCursorAction(this); + setCursorAction.mSelection = prevSelection; + setCursorAction.mCursorTextPos = (.)startTextPos; + mData.mUndoManager.Add(setCursorAction); int minPos = mSelection.GetValueOrDefault().MinPos; int maxPos = mSelection.GetValueOrDefault().MaxPos; @@ -2365,12 +2396,12 @@ namespace IDE.ui int q = 0; var nc = trimmedStr.Count('\n'); - if(afterTrimEnd == 0) + if (afterTrimEnd == 0) { if (undoBatchStart != null) mData.mUndoManager.Add(undoBatchStart.mBatchEnd); - CursorLineAndColumn = startLineAndCol; + CursorLineAndColumn = startLineAndCol.Value; if (doComment == null) mSelection = null; @@ -2397,7 +2428,6 @@ namespace IDE.ui CursorToLineEnd(); int cursorEndPos = CursorTextPos; mSelection = .(minPos, cursorEndPos); - } else if ((doComment != true) && (trimmedStr.StartsWith("/*"))) { @@ -2408,7 +2438,7 @@ namespace IDE.ui mSelection = EditSelection(lastCharPos - 4, lastCharPos - 2); DeleteChar(); - if (doComment != null) + if (prevSelection != null) mSelection = EditSelection(firstCharPos, lastCharPos - 4); } } @@ -2416,9 +2446,9 @@ namespace IDE.ui || nc >= 1 && (SafeGetChar(maxPos-1) != ' ' && SafeGetChar(maxPos-1) != '\t') && SafeGetChar(maxPos-1) != '\n')) { //if selection is from beginning of the line then we want to use // comment, that's why the check for line count and ' ' and tab CursorTextPos = firstCharPos; - if (noStar) { + if (doLineComment) + { CursorTextPos = minPos; - InsertAtCursor("//"); //goes here if no selection } else @@ -2427,17 +2457,17 @@ namespace IDE.ui CursorTextPos = lastCharPos + 2; InsertAtCursor("*/"); } - if (!noStar && doComment != null) - mSelection = EditSelection(firstCharPos, lastCharPos + 4); + + mSelection = EditSelection(firstCharPos, lastCharPos + 4); + if (startTextPos <= minPos) + CursorLineAndColumn = startLineAndCol.Value; + else + CursorTextPos = startTextPos + 2; + startLineAndCol = null; } else if (doComment != false) { - while (firstCharPos >= 0 && SafeGetChar(firstCharPos) != '\n') - { - firstCharPos--; - } - - for (int i = firstCharPos + 1; i < maxPos + q; i++) + for (int i = firstCharPos; i < maxPos + q; i++) { CursorTextPos = i; // needed to add i < maxPos + q; for this to work with InsertAtCursor InsertAtCursor("//"); q++; q++; @@ -2457,9 +2487,10 @@ namespace IDE.ui if (undoBatchStart != null) mData.mUndoManager.Add(undoBatchStart.mBatchEnd); - CursorLineAndColumn = startLineAndCol; + if (startLineAndCol != null) + CursorLineAndColumn = startLineAndCol.Value; - if (doComment == null) + if (prevSelection == null) mSelection = null; return true; From 688d1f8dd116571b98e1f782a33105ed4e5a883e Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 21 Dec 2021 17:06:18 -0500 Subject: [PATCH 090/139] CommentLines improvements --- IDE/src/ui/SourceEditWidgetContent.bf | 50 +++++++++++++++++---------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/IDE/src/ui/SourceEditWidgetContent.bf b/IDE/src/ui/SourceEditWidgetContent.bf index edbdb723..37feda6a 100644 --- a/IDE/src/ui/SourceEditWidgetContent.bf +++ b/IDE/src/ui/SourceEditWidgetContent.bf @@ -2265,7 +2265,7 @@ namespace IDE.ui int maxPos = mSelection.GetValueOrDefault().MaxPos; mSelection = null; - while (minPos >= 0) + while (minPos > 0) { var c = mData.mText[minPos - 1].mChar; if (c == '\n') @@ -2279,7 +2279,35 @@ namespace IDE.ui for (int i = minPos; i < maxPos; i++) { - bool isSpace = false; + var c = mData.mText[i].mChar; + if (didLineComment) + { + if (c == '\n') + { + didLineComment = false; + lineStartCol = 0; + } + continue; + } + if (c == '\t') + lineStartCol += 4; + else if (c == ' ') + lineStartCol++; + else + { + if (wantLineCol == -1) + wantLineCol = lineStartCol; + else + wantLineCol = Math.Min(wantLineCol, lineStartCol); + didLineComment = true; + } + } + wantLineCol = Math.Max(0, wantLineCol); + + didLineComment = false; + lineStartCol = 0; + for (int i = minPos; i < maxPos; i++) + { var c = mData.mText[i].mChar; if (didLineComment) { @@ -2296,27 +2324,11 @@ namespace IDE.ui commentNow = true; if (c == '\t') - { lineStartCol += 4; - isSpace = true; - } else if (c == ' ') - { lineStartCol++; - isSpace = true; - } - - if (!isSpace) - { - if (c == '\n') - { - - } - + else commentNow = true; - if (wantLineCol == -1) - wantLineCol = lineStartCol; - } if (commentNow) { From 8ff8ff0df1ddc6ddb74ba3cb42a868507b6997e2 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 21 Dec 2021 17:14:17 -0500 Subject: [PATCH 091/139] Make CommentBlock work when selection ends with ws at line start --- IDE/src/ui/SourceEditWidgetContent.bf | 32 +++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/IDE/src/ui/SourceEditWidgetContent.bf b/IDE/src/ui/SourceEditWidgetContent.bf index 37feda6a..3b951790 100644 --- a/IDE/src/ui/SourceEditWidgetContent.bf +++ b/IDE/src/ui/SourceEditWidgetContent.bf @@ -2272,6 +2272,38 @@ namespace IDE.ui break; minPos--; } + + bool hadMaxChar = false; + int checkMaxPos = maxPos; + while (checkMaxPos > 0) + { + var c = mData.mText[checkMaxPos - 1].mChar; + if (c == '\n') + break; + if ((c != '\t') && (c != ' ')) + { + hadMaxChar = true; + break; + } + checkMaxPos--; + } + + if (!hadMaxChar) + { + checkMaxPos = maxPos; + while (checkMaxPos < mData.mTextLength) + { + var c = mData.mText[checkMaxPos].mChar; + if (c == '\n') + break; + if ((c != '\t') && (c != ' ')) + { + maxPos = checkMaxPos + 1; + break; + } + checkMaxPos++; + } + } int wantLineCol = -1; int lineStartCol = 0; From a5794d210cd370408e662ec941580ceb20de389f Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 21 Dec 2021 18:11:46 -0500 Subject: [PATCH 092/139] Removed multi-line line commenting from ToggleComment --- IDE/src/ui/SourceEditWidgetContent.bf | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/IDE/src/ui/SourceEditWidgetContent.bf b/IDE/src/ui/SourceEditWidgetContent.bf index 3b951790..54367589 100644 --- a/IDE/src/ui/SourceEditWidgetContent.bf +++ b/IDE/src/ui/SourceEditWidgetContent.bf @@ -2437,9 +2437,6 @@ namespace IDE.ui int firstCharPos = minPos + (startLen - afterTrimStart); int lastCharPos = maxPos - (afterTrimStart - afterTrimEnd); - int q = 0; - var nc = trimmedStr.Count('\n'); - if (afterTrimEnd == 0) { if (undoBatchStart != null) @@ -2486,10 +2483,8 @@ namespace IDE.ui mSelection = EditSelection(firstCharPos, lastCharPos - 4); } } - else if (doComment != false && minPos >=0 && ((nc <= 1 && (SafeGetChar(minPos-1) != ' ' && SafeGetChar(minPos-1) != '\t') && SafeGetChar(minPos-1) != '\n') - || nc >= 1 && (SafeGetChar(maxPos-1) != ' ' && SafeGetChar(maxPos-1) != '\t') && SafeGetChar(maxPos-1) != '\n')) + else if (doComment != false) { //if selection is from beginning of the line then we want to use // comment, that's why the check for line count and ' ' and tab - CursorTextPos = firstCharPos; if (doLineComment) { CursorTextPos = minPos; @@ -2497,6 +2492,7 @@ namespace IDE.ui } else { + CursorTextPos = firstCharPos; InsertAtCursor("/*"); CursorTextPos = lastCharPos + 2; InsertAtCursor("*/"); @@ -2509,20 +2505,6 @@ namespace IDE.ui CursorTextPos = startTextPos + 2; startLineAndCol = null; } - else if (doComment != false) - { - for (int i = firstCharPos; i < maxPos + q; i++) - { - CursorTextPos = i; // needed to add i < maxPos + q; for this to work with InsertAtCursor - InsertAtCursor("//"); q++; q++; - - while (SafeGetChar(i) != '\n' && i < maxPos + q) - { - i++; - } - } - mSelection = EditSelection(minPos, maxPos + q); - } else { mSelection = prevSelection; From d3e5005814e2c3daffdab573129e0c66ff212534 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Wed, 22 Dec 2021 05:43:46 -0500 Subject: [PATCH 093/139] DoesLiteralFit selection fix --- IDEHelper/Compiler/BfExprEvaluator.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 265031d5..a8e74067 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -19770,7 +19770,7 @@ void BfExprEvaluator::Visit(BfIndexerExpression* indexerExpr) auto indexType = (BfPrimitiveType*)indexArgument.mType; - if (!mModule->mSystem->DoesLiteralFit(indexType->mTypeDef->mTypeCode, sizedArrayType->mElementCount)) + if (!mModule->mSystem->DoesLiteralFit(indexType->mTypeDef->mTypeCode, (int64)sizedArrayType->mElementCount)) { // We need to upsize the index so we can compare it against the larger elementCount indexType = mModule->GetPrimitiveType(BfTypeCode_IntPtr); @@ -22447,6 +22447,8 @@ void BfExprEvaluator::PerformBinaryOperation(BfType* resultType, BfIRValue convL mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConst(BfTypeCode_Boolean, 0), mModule->GetPrimitiveType(BfTypeCode_Boolean)); return; + default: + break; } } From ad46ac81e55278ecccf5c38903bfb881fda35c90 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Wed, 22 Dec 2021 05:53:49 -0500 Subject: [PATCH 094/139] Update VS download link --- IDE/src/IDEApp.bf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IDE/src/IDEApp.bf b/IDE/src/IDEApp.bf index ac1dcbf4..a43ce585 100644 --- a/IDE/src/IDEApp.bf +++ b/IDE/src/IDEApp.bf @@ -10795,7 +10795,7 @@ namespace IDE Beef requires the Microsoft C++ build tools for Visual Studio 2013 or later, but they don't seem to be installed. Install just Microsoft Visual C++ Build Tools or the entire Visual Studio suite from: - https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2019 + https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2022 """; #if CLI @@ -10806,7 +10806,7 @@ namespace IDE dlg.AddOkCancelButtons(new (dlg) => { ProcessStartInfo psi = scope ProcessStartInfo(); - psi.SetFileName("https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2019"); + psi.SetFileName("https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2022"); psi.UseShellExecute = true; psi.SetVerb("Open"); var process = scope SpawnedProcess(); From 0cd0c8905cf12ba386eb808910aee26deead5392 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Wed, 22 Dec 2021 09:55:52 -0500 Subject: [PATCH 095/139] Fixed issue typing '/' --- IDE/src/ui/SourceEditWidgetContent.bf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IDE/src/ui/SourceEditWidgetContent.bf b/IDE/src/ui/SourceEditWidgetContent.bf index 54367589..c9b2486f 100644 --- a/IDE/src/ui/SourceEditWidgetContent.bf +++ b/IDE/src/ui/SourceEditWidgetContent.bf @@ -3393,7 +3393,7 @@ namespace IDE.ui return; } - if ((keyChar == '/') && (ToggleComment())) + if ((keyChar == '/') && (HasSelection()) && (ToggleComment())) { return; } From a5a8ae90763831343d07fa3d33765607624fabef Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Wed, 22 Dec 2021 13:35:25 -0500 Subject: [PATCH 096/139] Mangle fix - name set when it should append --- IDEHelper/Compiler/BfModule.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 2f4cad4f..d085677a 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -11835,7 +11835,7 @@ bool BfModule::TryGetConstString(BfIRConstHolder* constHolder, BfIRValue irValue BfStringPoolEntry* entry = NULL; if (mContext->mStringObjectIdMap.TryGetValue(stringId, &entry)) { - str = entry->mString; + str += entry->mString; } else { From 72c31e545cf8d370f7b39e66d13aa612ea6ce9cc Mon Sep 17 00:00:00 2001 From: disarray2077 <86157825+disarray2077@users.noreply.github.com> Date: Wed, 22 Dec 2021 16:00:41 -0300 Subject: [PATCH 097/139] Fix dynamic libraries in Linux and MacOS --- IDEHelper/Compiler/BfSystem.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/IDEHelper/Compiler/BfSystem.cpp b/IDEHelper/Compiler/BfSystem.cpp index 236f5406..a9d869ec 100644 --- a/IDEHelper/Compiler/BfSystem.cpp +++ b/IDEHelper/Compiler/BfSystem.cpp @@ -498,7 +498,9 @@ BfImportKind BfMethodDef::GetImportKindFromPath(const StringImpl& filePath) { String fileExt = GetFileExtension(filePath); - if ((fileExt.Equals(".DLL", StringImpl::CompareKind_OrdinalIgnoreCase)) || + if ((fileExt.Equals(".DYLIB", StringImpl::CompareKind_OrdinalIgnoreCase)) || + (fileExt.Equals(".SO", StringImpl::CompareKind_OrdinalIgnoreCase)) || + (fileExt.Equals(".DLL", StringImpl::CompareKind_OrdinalIgnoreCase)) || (fileExt.Equals(".EXE", StringImpl::CompareKind_OrdinalIgnoreCase))) { return BfImportKind_Import_Dynamic; From 96f2e07fb88bfc0909ed3c374cf905bc5a74b859 Mon Sep 17 00:00:00 2001 From: unknown <81806010+marsej@users.noreply.github.com> Date: Thu, 23 Dec 2021 02:19:56 +0200 Subject: [PATCH 098/139] Fix flaky ShowErrorNext and random re-ordering in ErrorsPanel --- IDE/src/ui/ErrorsPanel.bf | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/IDE/src/ui/ErrorsPanel.bf b/IDE/src/ui/ErrorsPanel.bf index f64e2724..482d516d 100644 --- a/IDE/src/ui/ErrorsPanel.bf +++ b/IDE/src/ui/ErrorsPanel.bf @@ -136,17 +136,15 @@ namespace IDE.ui ClearAndDeleteItems(mResolveErrors); mResolveErrors.Capacity = mResolveErrors.Count; } - + var bfl = scope:: List(); for (int32 errorIdx = 0; errorIdx < errorCount; errorIdx++) { BfPassInstance.BfError bfError = new BfPassInstance.BfError(); passInstance.GetErrorData(errorIdx, bfError, true); + if (bfError.mFilePath == null) + bfError.mFilePath = new String(""); //for sort below - if (bfError.mIsWarning) - mWarningCount++; - else - mErrorCount++; - + bfl.Add(bfError); for (int32 moreInfoIdx < bfError.mMoreInfoCount) { BfPassInstance.BfError moreInfo = new BfPassInstance.BfError(); @@ -155,12 +153,26 @@ namespace IDE.ui bfError.mMoreInfo = new List(); bfError.mMoreInfo.Add(moreInfo); } + } + + function int(int lhs, int rhs) ascLambda = (lhs, rhs) => lhs <=> rhs; + bfl.Sort(scope (lhs, rhs) => ascLambda(lhs.mFilePath.GetHashCode()+lhs.mSrcStart, rhs.mFilePath.GetHashCode()+rhs.mSrcStart)); + + for (int32 errorIdx = 0; errorIdx < bfl.Count; errorIdx++) + { + var bfError = bfl[errorIdx]; + + if (bfError.mIsWarning) + { + mWarningCount++; + } + else + mErrorCount++; if (passKind == .Parse) { if (bfError.mFilePath == null) bfError.mFilePath = new String(""); - bool added = mParseErrors.TryAdd(bfError.mFilePath, var keyPtr, var valuePtr); if (added) { @@ -169,8 +181,9 @@ namespace IDE.ui } (*valuePtr).Add(bfError); } - else + else { mResolveErrors.Add(bfError); + } mDataId++; } @@ -354,7 +367,6 @@ namespace IDE.ui public override void Update() { base.Update(); - if (!mVisible) { // Very dirty @@ -369,6 +381,7 @@ namespace IDE.ui else mDirtyTicks++; + if(mDirtyTicks==0) ProcessErrors(); } @@ -379,6 +392,7 @@ namespace IDE.ui public void ShowErrorNext() { + if(mDirtyTicks==0) ProcessErrors(); bool foundFocused = false; From 70c41dbfc39e7f89e856006f6a7575e5ad7b8cd5 Mon Sep 17 00:00:00 2001 From: unknown <81806010+marsej@users.noreply.github.com> Date: Thu, 23 Dec 2021 02:25:37 +0200 Subject: [PATCH 099/139] Fix whitespace --- IDE/src/ui/ErrorsPanel.bf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/IDE/src/ui/ErrorsPanel.bf b/IDE/src/ui/ErrorsPanel.bf index 482d516d..c886adea 100644 --- a/IDE/src/ui/ErrorsPanel.bf +++ b/IDE/src/ui/ErrorsPanel.bf @@ -181,9 +181,8 @@ namespace IDE.ui } (*valuePtr).Add(bfError); } - else { - mResolveErrors.Add(bfError); - } + else + mResolveErrors.Add(bfError); mDataId++; } @@ -367,6 +366,7 @@ namespace IDE.ui public override void Update() { base.Update(); + if (!mVisible) { // Very dirty From 3676825b123d4e9abc6dd991d658b76b9b3cab23 Mon Sep 17 00:00:00 2001 From: unknown <81806010+marsej@users.noreply.github.com> Date: Thu, 23 Dec 2021 02:27:57 +0200 Subject: [PATCH 100/139] Fix whitespace --- IDE/src/ui/ErrorsPanel.bf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IDE/src/ui/ErrorsPanel.bf b/IDE/src/ui/ErrorsPanel.bf index c886adea..edf63cc3 100644 --- a/IDE/src/ui/ErrorsPanel.bf +++ b/IDE/src/ui/ErrorsPanel.bf @@ -153,7 +153,7 @@ namespace IDE.ui bfError.mMoreInfo = new List(); bfError.mMoreInfo.Add(moreInfo); } - } + } function int(int lhs, int rhs) ascLambda = (lhs, rhs) => lhs <=> rhs; bfl.Sort(scope (lhs, rhs) => ascLambda(lhs.mFilePath.GetHashCode()+lhs.mSrcStart, rhs.mFilePath.GetHashCode()+rhs.mSrcStart)); From 33355360817f694d5581e4578588ebdbf335e8f2 Mon Sep 17 00:00:00 2001 From: unknown <81806010+marsej@users.noreply.github.com> Date: Thu, 23 Dec 2021 02:33:14 +0200 Subject: [PATCH 101/139] Fix whitespace --- IDE/src/ui/ErrorsPanel.bf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IDE/src/ui/ErrorsPanel.bf b/IDE/src/ui/ErrorsPanel.bf index edf63cc3..be5f5fbb 100644 --- a/IDE/src/ui/ErrorsPanel.bf +++ b/IDE/src/ui/ErrorsPanel.bf @@ -382,7 +382,7 @@ namespace IDE.ui mDirtyTicks++; if(mDirtyTicks==0) - ProcessErrors(); + ProcessErrors(); } public void SetNeedsResolveAll() @@ -393,7 +393,7 @@ namespace IDE.ui public void ShowErrorNext() { if(mDirtyTicks==0) - ProcessErrors(); + ProcessErrors(); bool foundFocused = false; let root = mErrorLV.GetRoot(); From 6e988b90aa71bd06d300b397321ca2ca680f4590 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Thu, 23 Dec 2021 06:29:25 -0500 Subject: [PATCH 102/139] Moved default 'Comment Lines' to 'Ctrl+K, Ctrl+/' --- BeefLibs/Beefy2D/src/widgets/KeyCode.bf | 16 +++++++++++++++- IDE/src/Commands.bf | 6 +++--- IDE/src/Settings.bf | 3 ++- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/BeefLibs/Beefy2D/src/widgets/KeyCode.bf b/BeefLibs/Beefy2D/src/widgets/KeyCode.bf index 74c32e7d..00e1f9f0 100644 --- a/BeefLibs/Beefy2D/src/widgets/KeyCode.bf +++ b/BeefLibs/Beefy2D/src/widgets/KeyCode.bf @@ -90,13 +90,13 @@ namespace Beefy.widgets Minus = 0xBD, Period = 0xBE, Slash = 0xBF, + Tilde = 0xC0, Grave = 0xC0, LBracket = 0xDB, Backslash = 0xDC, RBracket = 0xDD, Apostrophe = 0xDE, Backtick = 0xDF, - Tilde = 0xC0, Command = 0xF0, COUNT = 0xFF, @@ -141,6 +141,16 @@ namespace Beefy.widgets return (KeyCode)LBracket; if (c == ']') return (KeyCode)RBracket; + if (c == '/') + return (KeyCode)Slash; + if (c == '\\') + return (KeyCode)Backslash; + if (c == '`') + return (KeyCode)Tilde; + if (c == '.') + return (KeyCode)Period; + if (c == ',') + return (KeyCode)Comma; } if (str.StartsWith("0x")) @@ -168,6 +178,10 @@ namespace Beefy.widgets c = '['; case RBracket: c = ']'; + case .Slash: + c = '/'; + case .Backslash: + c = '\\'; default: } if (c != 0) diff --git a/IDE/src/Commands.bf b/IDE/src/Commands.bf index 3ba093c2..72ae06ba 100644 --- a/IDE/src/Commands.bf +++ b/IDE/src/Commands.bf @@ -194,9 +194,9 @@ namespace IDE Add("Close Document", new () => { gApp.[Friend]TryCloseCurrentDocument(); }); Add("Close Panel", new () => { gApp.[Friend]TryCloseCurrentPanel(); }); Add("Close Workspace", new => gApp.[Friend]Cmd_CloseWorkspaceAndSetupNew); - Add("Comment Block", new => gApp.[Friend]CommentBlock); - Add("Comment Lines", new => gApp.[Friend]CommentLines); - Add("Comment Toggle", new => gApp.[Friend]CommentToggle); + Add("Comment Block", new => gApp.[Friend]CommentBlock, .Editor); + Add("Comment Lines", new => gApp.[Friend]CommentLines, .Editor); + Add("Comment Toggle", new => gApp.[Friend]CommentToggle, .Editor); Add("Compile File", new => gApp.Cmd_CompileFile); Add("Debug All Tests", new () => { gApp.[Friend]RunTests(true, true); }); Add("Debug Normal Tests", new () => { gApp.[Friend]RunTests(false, true); }); diff --git a/IDE/src/Settings.bf b/IDE/src/Settings.bf index ba5e5d39..5ef7348f 100644 --- a/IDE/src/Settings.bf +++ b/IDE/src/Settings.bf @@ -757,7 +757,8 @@ namespace IDE Add("Close Document", "Ctrl+W"); Add("Compile File", "Ctrl+F7"); Add("Comment Block", "Ctrl+K, Ctrl+C"); - Add("Comment Lines", "Ctrl+K, Ctrl+L"); + Add("Comment Lines", "Ctrl+K, Ctrl+/"); + Add("Comment Toggle", "Ctrl+K, Ctrl+T"); Add("Duplicate Line", "Ctrl+D"); Add("Find Class", "Alt+Shift+L"); Add("Find in Document", "Ctrl+F"); From e2337e7ac16c1ae969ff9a5c924b95ddf050e9fb Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Thu, 23 Dec 2021 07:07:03 -0500 Subject: [PATCH 103/139] Fixed issue clearing duplicate key binds --- IDE/src/Commands.bf | 24 ++++++++++++++++++++++-- IDE/src/Settings.bf | 6 ++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/IDE/src/Commands.bf b/IDE/src/Commands.bf index 72ae06ba..c3422655 100644 --- a/IDE/src/Commands.bf +++ b/IDE/src/Commands.bf @@ -9,7 +9,7 @@ namespace IDE { public KeyCode mKeyCode; public KeyFlags mKeyFlags; - + public int GetHashCode() { return (int)mKeyCode | (int)mKeyFlags << 16; @@ -121,10 +121,21 @@ namespace IDE class CommandMap : IDECommandBase { public Dictionary mMap = new .() ~ delete _; + public List mFailValues ~ delete _; + + public List FailValues + { + get + { + if (mFailValues == null) + mFailValues = new .(); + return mFailValues; + } + } public void Clear() { - for (let val in mMap.Values) + void Release(IDECommandBase val) { if (var cmdMap = val as CommandMap) delete cmdMap; @@ -136,6 +147,15 @@ namespace IDE ideCommand.mNext = null; } } + + for (let val in mMap.Values) + Release(val); + if (mFailValues != null) + { + for (var val in mFailValues) + Release(val); + mFailValues.Clear(); + } mMap.Clear(); } diff --git a/IDE/src/Settings.bf b/IDE/src/Settings.bf index 5ef7348f..30e51db1 100644 --- a/IDE/src/Settings.bf +++ b/IDE/src/Settings.bf @@ -894,7 +894,10 @@ namespace IDE { curCmdMap = (*valuePtr) as CommandMap; if (curCmdMap == null) + { + curCmdMap.FailValues.Add(ideCommand); break; + } } else { @@ -907,7 +910,10 @@ namespace IDE if (checkPrevCmd.mContextFlags == ideCommand.mContextFlags) gApp.OutputLineSmart("ERROR: The same key is bound for '{0}' and '{1}'", checkPrevCmd.mName, entry.mCommand); if (checkPrevCmd.mNext == null) + { + curCmdMap.FailValues.Add(ideCommand); break; + } checkPrevCmd = checkPrevCmd.mNext; } checkPrevCmd.mNext = ideCommand; From 6c2d03c898c6a73d19d66f7f8e86de89709ffe08 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Thu, 23 Dec 2021 07:25:45 -0500 Subject: [PATCH 104/139] Removed erroneous assertion in DoImplicitArgCapture --- IDEHelper/Compiler/BfExprEvaluator.cpp | 3 +-- IDEHelper/Compiler/BfIRBuilder.cpp | 6 ++++-- IDEHelper/Tests/src/FuncRefs.bf | 12 ++++++++++++ 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index a8e74067..039b4126 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -11480,8 +11480,7 @@ BfTypedValue BfExprEvaluator::DoImplicitArgCapture(BfAstNode* refNode, BfMethodI lookupVal = mModule->LoadValue(lookupVal); return lookupVal; } - } - BF_ASSERT(methodRefTarget.IsAddr()); + } if (paramType->IsComposite()) return BfTypedValue(mModule->mBfIRBuilder->CreateInBoundsGEP(methodRefTarget.mValue, 0, dataIdx), paramType, true); return BfTypedValue(mModule->ExtractValue(methodRefTarget, dataIdx), paramType); diff --git a/IDEHelper/Compiler/BfIRBuilder.cpp b/IDEHelper/Compiler/BfIRBuilder.cpp index 95307c23..57c74d92 100644 --- a/IDEHelper/Compiler/BfIRBuilder.cpp +++ b/IDEHelper/Compiler/BfIRBuilder.cpp @@ -2627,9 +2627,11 @@ void BfIRBuilder::CreateTypeDeclaration(BfType* type, bool forceDbgDefine) BfMethodInstance* methodInstance = methodRefType->mMethodRef; String name = "_BF_MethodRef_"; - name += BfTypeUtils::HashEncode64(methodInstance->mIdHash).c_str(); - if (wantDIData) + if (methodInstance != NULL) + name += BfTypeUtils::HashEncode64(methodInstance->mIdHash).c_str(); + + if ((wantDIData) && (methodInstance != NULL)) { auto typeDeclaration = methodInstance->GetOwner()->mTypeDef->mTypeDeclaration; diff --git a/IDEHelper/Tests/src/FuncRefs.bf b/IDEHelper/Tests/src/FuncRefs.bf index f63d4eaa..d30e8216 100644 --- a/IDEHelper/Tests/src/FuncRefs.bf +++ b/IDEHelper/Tests/src/FuncRefs.bf @@ -57,6 +57,14 @@ namespace Tests return dlg(val[0]); } + static void TestWrap(T del, bool b = false) where T : delegate void() + { + Action ac = scope () => { + del(); + }; + ac(); + } + [Test] public static void TestBasics() { @@ -78,6 +86,10 @@ namespace Tests List fList = scope .() { 1.2f, 2.3f }; Test.Assert(DoOnListA(fList, (val) => val + 100) == 101.2f); Test.Assert(DoOnListB((val) => val + 200, fList) == 201.2f); + + int a = 222; + TestWrap(() => { a += 100; }); + Test.Assert(a == 322); } struct MethodRefHolder where T : delegate int(int num) From 6e869c5ac55c905f97af889f130232b3f4e18752 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Thu, 23 Dec 2021 07:34:54 -0500 Subject: [PATCH 105/139] Fixed Quick Info command --- IDE/src/IDEApp.bf | 2 +- IDE/src/ui/SourceViewPanel.bf | 19 ++++++++++++++++++- IDEHelper/Compiler/BfExprEvaluator.cpp | 2 +- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/IDE/src/IDEApp.bf b/IDE/src/IDEApp.bf index a43ce585..51d9d475 100644 --- a/IDE/src/IDEApp.bf +++ b/IDE/src/IDEApp.bf @@ -3957,7 +3957,7 @@ namespace IDE if (sourceViewPanel != null) { if (sourceViewPanel.mEditWidget.mEditWidgetContent.GetCursorLineChar(var line, var lineChar)) - sourceViewPanel.UpdateMouseover(true, true, line, lineChar); + sourceViewPanel.UpdateMouseover(true, true, line, lineChar, true); } } diff --git a/IDE/src/ui/SourceViewPanel.bf b/IDE/src/ui/SourceViewPanel.bf index c1d98643..e3867de8 100644 --- a/IDE/src/ui/SourceViewPanel.bf +++ b/IDE/src/ui/SourceViewPanel.bf @@ -160,6 +160,8 @@ namespace IDE.ui { public int32 mCursorPos; public String mResult ~ delete _; + public int32? mLine; + public int32? mLineChar; public ~this() { @@ -4722,7 +4724,7 @@ namespace IDE.ui delete parser; } - public void UpdateMouseover(bool mouseoverFired, bool mouseInbounds, int line, int lineChar) + public void UpdateMouseover(bool mouseoverFired, bool mouseInbounds, int line, int lineChar, bool isManual = false) { @@ -5008,6 +5010,11 @@ namespace IDE.ui mHoverResolveTask = new HoverResolveTask(); mHoverResolveTask.mCursorPos = (int32)textIdx; + if (isManual) + { + mHoverResolveTask.mLine = (.)line; + mHoverResolveTask.mLineChar = (.)lineChar; + } } } @@ -5201,6 +5208,16 @@ namespace IDE.ui #if IDE_C_SUPPORT hasClangHoverErrorData = mClangHoverErrorData != null; #endif + + if (mHoverResolveTask != null) + { + if (mHoverResolveTask.mLine != null) + { + UpdateMouseover(true, true, mHoverResolveTask.mLine.Value, mHoverResolveTask.mLineChar.Value, true); + return; + } + } + if (((mouseoverFired) || (mHoverWatch != null) || (hasClangHoverErrorData) || (mHoverResolveTask?.mResult != null)) && (mousePos.x >= 0)) { diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 039b4126..9bd0fa6f 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -11441,7 +11441,7 @@ BfTypedValue BfExprEvaluator::DoImplicitArgCapture(BfAstNode* refNode, BfMethodI BfMethodInstance* methodRefMethodInst = methodRefType->mMethodRef; BF_ASSERT(methodRefMethodInst == methodInstance); - + auto paramType = methodInstance->GetParamType(paramIdx); int dataIdx = methodRefType->GetDataIdxFromParamIdx(paramIdx); From 2ccfd9e2d87e80107bf2fef50c0cc0f6de6412cb Mon Sep 17 00:00:00 2001 From: disarray2077 <86157825+disarray2077@users.noreply.github.com> Date: Thu, 23 Dec 2021 18:36:07 -0300 Subject: [PATCH 106/139] Fix Initializer Go To Definition --- IDEHelper/Compiler/BfExprEvaluator.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 9bd0fa6f..4f803a74 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -10200,6 +10200,17 @@ void BfExprEvaluator::Visit(BfInitializerExpression* initExpr) if ((fieldResult) || (mPropDef != NULL)) { + if (mResultFieldInstance != NULL) + { + auto autoComplete = GetAutoComplete(); + if ((autoComplete != NULL) && (autoComplete->IsAutocompleteNode(identifierNode))) + { + auto fieldDef = mResultFieldInstance->GetFieldDef(); + if (fieldDef != NULL) + autoComplete->SetDefinitionLocation(fieldDef->GetRefNode()); + } + } + mResult = fieldResult; PerformAssignment(assignExpr, true, BfTypedValue()); mResult = BfTypedValue(); From f7b6bf4ba21831defe62dc74d59b70f480fd304c Mon Sep 17 00:00:00 2001 From: disarray2077 <86157825+disarray2077@users.noreply.github.com> Date: Thu, 23 Dec 2021 19:06:38 -0300 Subject: [PATCH 107/139] Fix Property Go To Definition --- IDEHelper/Compiler/BfExprEvaluator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 9bd0fa6f..5628371e 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -4919,7 +4919,7 @@ BfTypedValue BfExprEvaluator::LookupField(BfAstNode* targetSrc, BfTypedValue tar if ((autoComplete != NULL) && (autoComplete->IsAutocompleteNode(targetSrc))) { if (autoComplete->mIsGetDefinition) - autoComplete->SetDefinitionLocation(basePropDef->GetRefNode(), true); + autoComplete->SetDefinitionLocation(basePropDef->GetRefNode()); autoComplete->mDefProp = basePropDef; autoComplete->mDefType = baseTypeInst->mTypeDef; } From 905ccae64c06e6d045ed259a32a38d78867633f1 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 27 Dec 2021 06:17:14 -0500 Subject: [PATCH 108/139] Fixed cursor up/down when there's a selection --- BeefLibs/Beefy2D/src/widgets/EditWidget.bf | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/BeefLibs/Beefy2D/src/widgets/EditWidget.bf b/BeefLibs/Beefy2D/src/widgets/EditWidget.bf index cf92c840..b2494d92 100644 --- a/BeefLibs/Beefy2D/src/widgets/EditWidget.bf +++ b/BeefLibs/Beefy2D/src/widgets/EditWidget.bf @@ -2366,7 +2366,14 @@ namespace Beefy.widgets case KeyCode.Down: { int32 aDir = (keyCode == KeyCode.Up) ? -1 : 1; - bool didSelectionMove = PrepareForCursorMove(aDir); + if ((mSelection != null) && (!mWidgetWindow.IsKeyDown(KeyCode.Shift))) + { + var lineAndCol = CursorLineAndColumn; + var usePos = (aDir < 0) ? (int32)mSelection.Value.MinPos : mSelection.Value.MaxPos; + GetLineCharAtIdx(usePos, var selLine, var selLineChar); + CursorLineAndColumn = .(selLine, lineAndCol.mColumn); + mSelection = null; + } GetCursorLineChar(out lineIdx, out lineChar); @@ -2403,9 +2410,6 @@ namespace Beefy.widgets mCursorWantX = wantedX; } - - if (didSelectionMove) - CursorToLineStart(false); } break; case KeyCode.Home: From 33204ff59979069d33f1cd4254f7df95710a5111 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 27 Dec 2021 06:47:46 -0500 Subject: [PATCH 109/139] Evaluate mixin result as expression in mixin definition --- IDEHelper/Compiler/BfStmtEvaluator.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/IDEHelper/Compiler/BfStmtEvaluator.cpp b/IDEHelper/Compiler/BfStmtEvaluator.cpp index e9919b51..27fe5279 100644 --- a/IDEHelper/Compiler/BfStmtEvaluator.cpp +++ b/IDEHelper/Compiler/BfStmtEvaluator.cpp @@ -3455,7 +3455,9 @@ void BfModule::VisitCodeBlock(BfBlock* block) } else if ((mCurMethodInstance->IsMixin()) && (mCurMethodState->mCurScope == &mCurMethodState->mHeadScope)) { - // Silently allow... + // Only in mixin definition - result ignored + CreateValueFromExpression(expr); + break; } else { From fe9286f41c18a872c4af846a62858da7ee3437d4 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 27 Dec 2021 09:35:34 -0500 Subject: [PATCH 110/139] Fix small selection issues after uncomment --- IDE/src/ui/SourceEditWidgetContent.bf | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/IDE/src/ui/SourceEditWidgetContent.bf b/IDE/src/ui/SourceEditWidgetContent.bf index c9b2486f..f9363bf5 100644 --- a/IDE/src/ui/SourceEditWidgetContent.bf +++ b/IDE/src/ui/SourceEditWidgetContent.bf @@ -2390,6 +2390,19 @@ namespace IDE.ui return true; } + void FixSelection() + { + if (!HasSelection()) + return; + if (CursorTextPos >= mSelection.Value.MaxPos) + CursorTextPos = mSelection.Value.MaxPos; + if (mSelection.Value.MaxPos - mSelection.Value.MinPos <= 1) + { + mSelection = null; + return; + } + } + public bool ToggleComment(bool? doComment = null) { if (CheckReadOnly()) @@ -2519,6 +2532,8 @@ namespace IDE.ui if (prevSelection == null) mSelection = null; + FixSelection(); + return true; } From da586107360f9c4ba81298e128f36ddf6aed5536 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 27 Dec 2021 09:35:54 -0500 Subject: [PATCH 111/139] HasSelection fix for cursor up/down --- BeefLibs/Beefy2D/src/widgets/EditWidget.bf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BeefLibs/Beefy2D/src/widgets/EditWidget.bf b/BeefLibs/Beefy2D/src/widgets/EditWidget.bf index b2494d92..7267ce07 100644 --- a/BeefLibs/Beefy2D/src/widgets/EditWidget.bf +++ b/BeefLibs/Beefy2D/src/widgets/EditWidget.bf @@ -2366,7 +2366,7 @@ namespace Beefy.widgets case KeyCode.Down: { int32 aDir = (keyCode == KeyCode.Up) ? -1 : 1; - if ((mSelection != null) && (!mWidgetWindow.IsKeyDown(KeyCode.Shift))) + if ((HasSelection()) && (!mWidgetWindow.IsKeyDown(KeyCode.Shift))) { var lineAndCol = CursorLineAndColumn; var usePos = (aDir < 0) ? (int32)mSelection.Value.MinPos : mSelection.Value.MaxPos; From f13fc76cd00fecf5d9e1c095efd970f7f0ef03c8 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 27 Dec 2021 10:01:03 -0500 Subject: [PATCH 112/139] Fixed case where tuple has `var` member --- IDEHelper/Compiler/BfModuleTypeUtils.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 7a93ce43..d6a3b689 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -10569,8 +10569,11 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula wantGeneric = true; if (type->IsUnspecializedType()) isUnspecialized = true; - BF_ASSERT(!type->IsVar()); - + if (type->IsVar()) + { + mContext->mResolvedTypes.RemoveEntry(resolvedEntry); + return ResolveTypeResult(typeRef, NULL, populateType, resolveFlags); + } types.push_back(type); names.push_back(fieldName); } From 32fb5956aac8a262921b01fae1b9ec9c9279b3de Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 27 Dec 2021 10:21:34 -0500 Subject: [PATCH 113/139] Bump to c++17 --- IDEHelper/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IDEHelper/CMakeLists.txt b/IDEHelper/CMakeLists.txt index 46a478e9..a107fb24 100644 --- a/IDEHelper/CMakeLists.txt +++ b/IDEHelper/CMakeLists.txt @@ -122,7 +122,7 @@ if(MSVC) set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /W3 /GL /Od /Oi /Gy /EHsc") endif(MSVC) if(NOT MSVC) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-rtti -Wno-multichar -Wno-invalid-offsetof") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -fno-rtti -Wno-multichar -Wno-invalid-offsetof") endif(NOT MSVC) ################ Files ################ From 8e543d8cc5dca8478fdeadee83237dc392c9633e Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 27 Dec 2021 10:21:47 -0500 Subject: [PATCH 114/139] Support for generic attributes --- IDEHelper/Compiler/BfModuleTypeUtils.cpp | 9 ++++++--- IDEHelper/Compiler/BfResolvedTypeUtils.cpp | 7 +++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index d6a3b689..d1201234 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -7583,7 +7583,7 @@ BfTypeDef* BfModule::ResolveGenericInstanceDef(BfGenericInstanceTypeRef* generic { BfTypeLookupError error; error.mRefNode = typeRef; - BfTypeDef* typeDef = FindTypeDef(typeRef, NULL, &error, numGenericParams); + BfTypeDef* typeDef = FindTypeDef(typeRef, NULL, &error, numGenericParams, resolveFlags); if (typeDef != NULL) { BfAutoComplete* autoComplete = NULL; @@ -7614,6 +7614,8 @@ BfTypeDef* BfModule::ResolveGenericInstanceDef(BfGenericInstanceTypeRef* generic if (typeRef->IsA()) { String findName = typeRef->ToString(); + if ((resolveFlags & BfResolveTypeRefFlag_Attribute) != 0) + findName += "Attribute"; if ((mCurTypeInstance != NULL) && (mCurTypeInstance->IsGenericTypeInstance())) { auto genericTypeInst = (BfTypeInstance*)mCurTypeInstance; @@ -10105,7 +10107,8 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula } BfResolvedTypeSet::LookupContext lookupCtx; - lookupCtx.mResolveFlags = (BfResolveTypeRefFlags)(resolveFlags & (BfResolveTypeRefFlag_NoCreate | BfResolveTypeRefFlag_IgnoreLookupError | BfResolveTypeRefFlag_DisallowComptime | BfResolveTypeRefFlag_AllowInferredSizedArray)); + lookupCtx.mResolveFlags = (BfResolveTypeRefFlags)(resolveFlags & (BfResolveTypeRefFlag_NoCreate | BfResolveTypeRefFlag_IgnoreLookupError | + BfResolveTypeRefFlag_DisallowComptime | BfResolveTypeRefFlag_AllowInferredSizedArray | BfResolveTypeRefFlag_Attribute)); lookupCtx.mRootTypeRef = typeRef; lookupCtx.mRootTypeDef = typeDef; lookupCtx.mModule = this; @@ -10382,7 +10385,7 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula BfTypeVector genericArgs; BfType* type = NULL; - BfTypeDef* typeDef = ResolveGenericInstanceDef(genericTypeInstRef, &type); + BfTypeDef* typeDef = ResolveGenericInstanceDef(genericTypeInstRef, &type, resolveFlags); if(ambiguousTypeDef != NULL) ShowAmbiguousTypeError(typeRef, typeDef, ambiguousTypeDef); if (typeDef == NULL) diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp index 26ba94bc..3e4e49f2 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp @@ -3021,7 +3021,8 @@ int BfResolvedTypeSet::DirectHash(BfTypeReference* typeRef, LookupContext* ctx, BfResolveTypeRefFlags resolveFlags = ctx->mResolveFlags; if ((flags & BfHashFlag_AllowGenericParamConstValue) != 0) resolveFlags = (BfResolveTypeRefFlags)(resolveFlags | BfResolveTypeRefFlag_AllowGenericParamConstValue); - + if (!isHeadType) + resolveFlags = (BfResolveTypeRefFlags)(resolveFlags &~ BfResolveTypeRefFlag_Attribute); auto resolvedType = ctx->mModule->ResolveTypeRef(typeRef, BfPopulateType_Identity, resolveFlags); if (resolvedType == NULL) { @@ -3917,7 +3918,9 @@ bool BfResolvedTypeSet::GenericTypeEquals(BfTypeInstance* lhsGenericType, BfType return false; } - BfTypeDef* elementTypeDef = ctx->mModule->ResolveGenericInstanceDef(rhsGenericTypeInstRef); + BfTypeDef* elementTypeDef = ctx->mModule->ResolveGenericInstanceDef(rhsGenericTypeInstRef, NULL, ctx->mResolveFlags); + if (elementTypeDef == NULL) + return false; if (elementTypeDef->GetDefinition() != lhsGenericType->mTypeDef->GetDefinition()) return false; From bf9753f8a276e4137949ce802ec1f36642fce258 Mon Sep 17 00:00:00 2001 From: disarray2077 <86157825+disarray2077@users.noreply.github.com> Date: Mon, 27 Dec 2021 12:38:33 -0300 Subject: [PATCH 115/139] Add methods PadLeft/PadRight and Equals(StringView) to String class --- BeefLibs/corlib/src/String.bf | 46 +++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/BeefLibs/corlib/src/String.bf b/BeefLibs/corlib/src/String.bf index d243f8de..25bc0c8d 100644 --- a/BeefLibs/corlib/src/String.bf +++ b/BeefLibs/corlib/src/String.bf @@ -1965,6 +1965,22 @@ namespace System return EqualsIgnoreCaseHelper(a.Ptr, b.Ptr, a.mLength); return EqualsHelper(a.Ptr, b.Ptr, a.mLength); } + + public bool Equals(StringView str) + { + if (mLength != str.[Friend]mLength) + return false; + return EqualsHelper(str.Ptr, mPtr, mLength); + } + + public bool Equals(StringView str, StringComparison comparisonType = StringComparison.Ordinal) + { + if (mLength != str.[Friend]mLength) + return false; + if (comparisonType == StringComparison.OrdinalIgnoreCase) + return EqualsIgnoreCaseHelper(str.Ptr, mPtr, mLength); + return EqualsHelper(str.Ptr, mPtr, mLength); + } public bool StartsWith(StringView b, StringComparison comparisonType = StringComparison.Ordinal) { @@ -2278,6 +2294,36 @@ namespace System TrimStart((.)trimChar); TrimEnd((.)trimChar); } + + public void PadLeft(int totalWidth, char8 paddingChar) + { + Insert(0, paddingChar, totalWidth - Length); + } + + public void PadLeft(int totalWidth, char32 paddingChar) + { + Insert(0, paddingChar, totalWidth - Length); + } + + public void PadLeft(int totalWidth) + { + Insert(0, ' ', totalWidth - Length); + } + + public void PadRight(int totalWidth, char8 paddingChar) + { + Append(paddingChar, totalWidth - Length); + } + + public void PadRight(int totalWidth, char32 paddingChar) + { + Append(paddingChar, totalWidth - Length); + } + + public void PadRight(int totalWidth) + { + Append(' ', totalWidth - Length); + } public void Join(StringView sep, IEnumerator enumerable) { From 60c0377d95b7487dad257dc5f44d7c1d7814cfa9 Mon Sep 17 00:00:00 2001 From: disarray2077 <86157825+disarray2077@users.noreply.github.com> Date: Mon, 27 Dec 2021 13:45:52 -0300 Subject: [PATCH 116/139] Add IsDefined, GetValues and GetNames to Enum class --- BeefLibs/corlib/src/Enum.bf | 118 ++++++++++++++++++++++++++++++++++-- 1 file changed, 112 insertions(+), 6 deletions(-) diff --git a/BeefLibs/corlib/src/Enum.bf b/BeefLibs/corlib/src/Enum.bf index f39872e1..1137494e 100644 --- a/BeefLibs/corlib/src/Enum.bf +++ b/BeefLibs/corlib/src/Enum.bf @@ -30,12 +30,118 @@ namespace System return .Err; } - /*public override void ToString(String strBuffer) mut + public static bool IsDefined(T value) + where T : enum { - Type type = GetType(); - int32* iPtr = (int32*)((int)(&this) + (int)type.Size); - EnumToString(type, strBuffer, *iPtr); - //EnumToString(GetType(), ) - }*/ + var typeInst = (TypeInstance)typeof(T); + for (var field in typeInst.GetFields()) + { + if (field.[Friend]mFieldData.[Friend]mData == (.)value) + return true; + } + + return false; + } + + public static readonly EnumValuesEnumerator GetValues() + where TEnum : enum + { + return .(); + } + + public static readonly EnumNamesEnumerator GetNames() + where TEnum : enum + { + return .(); + } + + private struct EnumFieldsEnumeratorWrapper + where TEnum : enum + { + FieldInfo.Enumerator mEnumerator; + + public this() + { + mEnumerator = typeof(TEnum).GetFields(); + } + + public int Index + { + get + { + return mEnumerator.Index; + } + } + + public int Count + { + get + { + return mEnumerator.mTypeInstance.[Friend]mFieldDataCount; + } + } + + public FieldInfo Current + { + get + { + return (.)mEnumerator.Current; + } + } + + public bool MoveNext() mut + { + return mEnumerator.MoveNext(); + } + + public void Dispose() + { + } + + public Result GetNext() mut + { + if (!MoveNext()) + return .Err; + return Current; + } + } + + public struct EnumValuesEnumerator : EnumFieldsEnumeratorWrapper, IEnumerator + where TEnum : enum + { + public new TEnum Current + { + get + { + return (.)base.Current.[Friend]mFieldData.[Friend]mData; + } + } + + public new Result GetNext() mut + { + if (!MoveNext()) + return .Err; + return Current; + } + } + + public struct EnumNamesEnumerator : EnumFieldsEnumeratorWrapper, IEnumerator + where TEnum : enum + { + public new StringView Current + { + get + { + return (.)base.Current.[Friend]mFieldData.[Friend]mName; + } + } + + public new Result GetNext() mut + { + if (!MoveNext()) + return .Err; + return Current; + } + } } } From b707bef001e5a6d582c634ae699299e60a037d08 Mon Sep 17 00:00:00 2001 From: disarray2077 <86157825+disarray2077@users.noreply.github.com> Date: Mon, 27 Dec 2021 14:22:22 -0300 Subject: [PATCH 117/139] Make Variant IDisposable --- BeefLibs/corlib/src/Variant.bf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BeefLibs/corlib/src/Variant.bf b/BeefLibs/corlib/src/Variant.bf index 5c736df6..825b5f96 100644 --- a/BeefLibs/corlib/src/Variant.bf +++ b/BeefLibs/corlib/src/Variant.bf @@ -2,7 +2,7 @@ using System.Diagnostics; namespace System { - struct Variant + struct Variant : IDisposable { enum ObjectType { @@ -472,4 +472,4 @@ namespace System return variant; } } -} \ No newline at end of file +} From 096ade761456066dcf4f66476216b16c59ec5ac2 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 27 Dec 2021 12:33:32 -0500 Subject: [PATCH 118/139] Remove warning for 32-bit --- BeefLibs/corlib/src/Collections/Dictionary.bf | 1 + 1 file changed, 1 insertion(+) diff --git a/BeefLibs/corlib/src/Collections/Dictionary.bf b/BeefLibs/corlib/src/Collections/Dictionary.bf index 1aaa7ccf..83219754 100644 --- a/BeefLibs/corlib/src/Collections/Dictionary.bf +++ b/BeefLibs/corlib/src/Collections/Dictionary.bf @@ -311,6 +311,7 @@ namespace System.Collections { if (sizeof(int) == 4) return (int32)hashCode & 0x7FFFFFFF; +#unwarn if (sizeof(int_cosize) == 8) return (int_cosize)(hashCode & 0x7FFFFFFF'FFFFFFFFL); return ((int32)hashCode ^ (int32)((int64)hashCode >> 33)) & 0x7FFFFFFF; From b9908cb4a8b9bd3b40e2594054dd072441ddc4a3 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 27 Dec 2021 12:55:14 -0500 Subject: [PATCH 119/139] Allow calling convention attributes --- BeefLibs/corlib/src/Attribute.bf | 4 +- BeefLibs/corlib/src/IO/Shell.bf | 48 +++++------ BeefLibs/corlib/src/Windows.bf | 96 +++++++++++----------- IDEHelper/Compiler/BfExprEvaluator.cpp | 2 +- IDEHelper/Compiler/BfModule.cpp | 41 ++++++--- IDEHelper/Compiler/BfModule.h | 12 ++- IDEHelper/Compiler/BfModuleTypeUtils.cpp | 54 +++++++++++- IDEHelper/Compiler/BfPrinter.cpp | 3 +- IDEHelper/Compiler/BfReducer.cpp | 53 +++++++++++- IDEHelper/Compiler/BfResolvedTypeUtils.cpp | 12 ++- IDEHelper/Compiler/BfResolvedTypeUtils.h | 8 +- 11 files changed, 240 insertions(+), 93 deletions(-) diff --git a/BeefLibs/corlib/src/Attribute.bf b/BeefLibs/corlib/src/Attribute.bf index 3a16088d..8549c43c 100644 --- a/BeefLibs/corlib/src/Attribute.bf +++ b/BeefLibs/corlib/src/Attribute.bf @@ -30,6 +30,8 @@ namespace System Delete = 0x80000, Alias = 0x100000, Block = 0x200000, + DelegateTypeRef = 0x400000, + FunctionTypeRef = 0x800000, Types = .Struct | .Enum | .Function | .Class | .Interface, ValueTypes = .Struct | .Enum | .Function, @@ -227,7 +229,7 @@ namespace System } - [AttributeUsage(.Method | .Constructor | .Delegate | .Function)] + [AttributeUsage(.Method | .Constructor | .Delegate | .Function | .DelegateTypeRef | .FunctionTypeRef)] public struct CallingConventionAttribute : Attribute { public enum Kind diff --git a/BeefLibs/corlib/src/IO/Shell.bf b/BeefLibs/corlib/src/IO/Shell.bf index 1c230313..41151db2 100644 --- a/BeefLibs/corlib/src/IO/Shell.bf +++ b/BeefLibs/corlib/src/IO/Shell.bf @@ -9,7 +9,7 @@ namespace System.IO { public struct VTable : COM_IUnknown.VTable { - public function HResult(COM_IPersistFile* self, Guid* pClassID) GetClassID; + public function [CallingConvention(.Stdcall)] HResult(COM_IPersistFile* self, Guid* pClassID) GetClassID; } } @@ -19,11 +19,11 @@ namespace System.IO public struct VTable : COM_IPersist.VTable { - public function HResult(COM_IPersistFile* self) IsDirty; - public function HResult(COM_IPersistFile* self, char16* pszFileName) Load; - public function HResult(COM_IPersistFile* self, char16* pszFileName, Windows.IntBool remember) Save; - public function HResult(COM_IPersistFile* self, char16* pszFileName) SaveCompleted; - public function HResult(COM_IPersistFile* self, char16* pszName) GetCurFile; + public function [CallingConvention(.Stdcall)] HResult(COM_IPersistFile* self) IsDirty; + public function [CallingConvention(.Stdcall)] HResult(COM_IPersistFile* self, char16* pszFileName) Load; + public function [CallingConvention(.Stdcall)] HResult(COM_IPersistFile* self, char16* pszFileName, Windows.IntBool remember) Save; + public function [CallingConvention(.Stdcall)] HResult(COM_IPersistFile* self, char16* pszFileName) SaveCompleted; + public function [CallingConvention(.Stdcall)] HResult(COM_IPersistFile* self, char16* pszName) GetCurFile; } public new VTable* VT { @@ -43,24 +43,24 @@ namespace System.IO public struct VTable : Windows.COM_IUnknown.VTable { - public function HResult(COM_IShellLink* self, char16* pszFile, int32 cch, Windows.NativeFindData* pfd, uint32 fFlags) GetPath; - public function HResult(COM_IShellLink* self, IDLIST** ppidl) GetIDList; - public function HResult(COM_IShellLink* self, IDLIST* pidl) SetIDList; - public function HResult(COM_IShellLink* self, char16* pszName, int32 cch) GetDescription; - public function HResult(COM_IShellLink* self, char16* pszName) SetDescription; - public function HResult(COM_IShellLink* self, char16* pszDir, int32 cch) GetWorkingDirectory; - public function HResult(COM_IShellLink* self, char16* pszDir) SetWorkingDirectory; - public function HResult(COM_IShellLink* self, char16* pszArgs, int32 cch) GetArguments; - public function HResult(COM_IShellLink* self, char16* pszArgs) SetArguments; - public function HResult(COM_IShellLink* self, uint16 *pwHotkey) GetHotkey; - public function HResult(COM_IShellLink* self, uint16 wHotkey) SetHotkey; - public function HResult(COM_IShellLink* self, int32 *piShowCmd) GetShowCmd; - public function HResult(COM_IShellLink* self, int32 iShowCmd) SetShowCmd; - public function HResult(COM_IShellLink* self, char16* pszIconPath, int32 cch, int32 *piIcon) GetIconLocation; - public function HResult(COM_IShellLink* self, char16* pszIconPath, int32 iIcon) SetIconLocation; - public function HResult(COM_IShellLink* self, char16* pszPathRel, uint32 dwReserved) SetRelativePath; - public function HResult(COM_IShellLink* self, Windows.HWnd hwnd, uint32 fFlags) Resolve; - public function HResult(COM_IShellLink* self, char16* pszFile) SetPath; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, char16* pszFile, int32 cch, Windows.NativeFindData* pfd, uint32 fFlags) GetPath; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, IDLIST** ppidl) GetIDList; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, IDLIST* pidl) SetIDList; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, char16* pszName, int32 cch) GetDescription; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, char16* pszName) SetDescription; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, char16* pszDir, int32 cch) GetWorkingDirectory; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, char16* pszDir) SetWorkingDirectory; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, char16* pszArgs, int32 cch) GetArguments; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, char16* pszArgs) SetArguments; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, uint16 *pwHotkey) GetHotkey; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, uint16 wHotkey) SetHotkey; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, int32 *piShowCmd) GetShowCmd; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, int32 iShowCmd) SetShowCmd; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, char16* pszIconPath, int32 cch, int32 *piIcon) GetIconLocation; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, char16* pszIconPath, int32 iIcon) SetIconLocation; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, char16* pszPathRel, uint32 dwReserved) SetRelativePath; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, Windows.HWnd hwnd, uint32 fFlags) Resolve; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellLink* self, char16* pszFile) SetPath; } public new VTable* VT diff --git a/BeefLibs/corlib/src/Windows.bf b/BeefLibs/corlib/src/Windows.bf index 23de97ad..b94d61c0 100644 --- a/BeefLibs/corlib/src/Windows.bf +++ b/BeefLibs/corlib/src/Windows.bf @@ -47,9 +47,9 @@ namespace System public struct VTable { - public function HResult(COM_IUnknown* self, ref Guid riid, void** result) QueryInterface; - public function uint32(COM_IUnknown* self) AddRef; - public function uint32(COM_IUnknown* self) Release; + public function [CallingConvention(.Stdcall)] HResult(COM_IUnknown* self, ref Guid riid, void** result) QueryInterface; + public function [CallingConvention(.Stdcall)] uint32(COM_IUnknown* self) AddRef; + public function [CallingConvention(.Stdcall)] uint32(COM_IUnknown* self) Release; } public enum HResult : int32 @@ -1124,13 +1124,13 @@ namespace System public struct VTable : Windows.COM_IUnknown.VTable { - public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog) OnFileOk; - public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog, COM_IShellItem* psiFolder) OnFolderChanging; - public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog) OnFolderChange; - public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog) OnSelectionChange; - public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog, FDE_SHAREVIOLATION_RESPONSE* pResponse) OnShareViolation; - public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog) OnTypeChange; - public function HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog, COM_IShellItem* shellItem, FDE_OVERWRITE_RESPONSE* response) OnOverwrite; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog) OnFileOk; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog, COM_IShellItem* psiFolder) OnFolderChanging; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog) OnFolderChange; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog) OnSelectionChange; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog, FDE_SHAREVIOLATION_RESPONSE* pResponse) OnShareViolation; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog) OnTypeChange; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialogEvents* self, COM_IFileDialog* fileDialog, COM_IShellItem* shellItem, FDE_OVERWRITE_RESPONSE* response) OnOverwrite; } } @@ -1154,11 +1154,11 @@ namespace System public struct VTable : Windows.COM_IUnknown.VTable { - public function HResult(COM_IShellItem* self, void* pbc, ref Guid bhid, ref Guid riid, void** ppv) BindToHandler; - public function HResult(COM_IShellItem* self, out COM_IShellItem* ppsi) GetParent; - public function HResult(COM_IShellItem* self, SIGDN sigdnName, out char16* ppszName) GetDisplayName; - public function HResult(COM_IShellItem* self, uint sfgaoMask, out uint psfgaoAttribs) GetAttributes; - public function HResult(COM_IShellItem* self, COM_IShellItem* psi, uint32 hint, out int32 piOrder) Compare; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellItem* self, void* pbc, ref Guid bhid, ref Guid riid, void** ppv) BindToHandler; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellItem* self, out COM_IShellItem* ppsi) GetParent; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellItem* self, SIGDN sigdnName, out char16* ppszName) GetDisplayName; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellItem* self, uint sfgaoMask, out uint psfgaoAttribs) GetAttributes; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellItem* self, COM_IShellItem* psi, uint32 hint, out int32 piOrder) Compare; } public new VTable* VT @@ -1207,13 +1207,13 @@ namespace System public struct VTable : Windows.COM_IUnknown.VTable { - public function HResult(COM_IShellItemArray* self, void* pbc, ref Guid rbhid, ref Guid riid, out void* ppvOut) BindToHandler; - public function HResult(COM_IShellItemArray* self, GETPROPERTYSTOREFLAGS flags, ref Guid riid, out void* ppv) GetPropertyStore; - public function HResult(COM_IShellItemArray* self, ref PROPERTYKEY keyType, ref Guid riid, out void* ppv) GetPropertyDescriptionList; - public function HResult(COM_IShellItemArray* self, SIATTRIBFLAGS dwAttribFlags, uint32 sfgaoMask, out uint32 psfgaoAttribs) GetAttributes; - public function HResult(COM_IShellItemArray* self, out uint32 pdwNumItems) GetCount; - public function HResult(COM_IShellItemArray* self, uint32 dwIndex, out COM_IShellItem* ppsi) GetItemAt; - public function HResult(COM_IShellItemArray* self, out void* ppenumShellItems) EnumItems; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellItemArray* self, void* pbc, ref Guid rbhid, ref Guid riid, out void* ppvOut) BindToHandler; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellItemArray* self, GETPROPERTYSTOREFLAGS flags, ref Guid riid, out void* ppv) GetPropertyStore; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellItemArray* self, ref PROPERTYKEY keyType, ref Guid riid, out void* ppv) GetPropertyDescriptionList; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellItemArray* self, SIATTRIBFLAGS dwAttribFlags, uint32 sfgaoMask, out uint32 psfgaoAttribs) GetAttributes; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellItemArray* self, out uint32 pdwNumItems) GetCount; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellItemArray* self, uint32 dwIndex, out COM_IShellItem* ppsi) GetItemAt; + public function [CallingConvention(.Stdcall)] HResult(COM_IShellItemArray* self, out void* ppenumShellItems) EnumItems; } public new VTable* VT { @@ -1268,30 +1268,30 @@ namespace System public struct VTable : Windows.COM_IUnknown.VTable { - public function HResult(COM_IFileDialog* self, Windows.HWnd parent) Show; - public function HResult(COM_IFileDialog* self, uint cFileTypes, COMDLG_FILTERSPEC* rgFilterSpec) SetFileTypes; - public function HResult(COM_IFileDialog* self, uint iFileType) SetFileTypeIndex; - public function HResult(COM_IFileDialog* self, out uint piFileType) GetFileTypeIndex; - public function HResult(COM_IFileDialog* self, COM_IFileDialogEvents* pfde, out uint pdwCookie) Advise; - public function HResult(COM_IFileDialog* self, uint dwCookie) Unadvise; - public function HResult(COM_IFileDialog* self, FOS fos) SetOptions; - public function HResult(COM_IFileDialog* self, out FOS pfos) GetOptions; - public function HResult(COM_IFileDialog* self, COM_IShellItem* psi) SetDefaultFolder; - public function HResult(COM_IFileDialog* self, COM_IShellItem* psi) SetFolder; - public function HResult(COM_IFileDialog* self, out COM_IShellItem* ppsi) GetFolder; - public function HResult(COM_IFileDialog* self, out COM_IShellItem* ppsi) GetCurrentSelection; - public function HResult(COM_IFileDialog* self, char16* pszName) SetFileName; - public function HResult(COM_IFileDialog* self, out char16* pszName) GetFileName; - public function HResult(COM_IFileDialog* self, char16* pszTitle) SetTitle; - public function HResult(COM_IFileDialog* self, char16* pszText) SetOkButtonLabel; - public function HResult(COM_IFileDialog* self, char16* pszLabel) SetFileNameLabel; - public function HResult(COM_IFileDialog* self, out COM_IShellItem* ppsi) GetResult; - public function HResult(COM_IFileDialog* self, COM_IShellItem* psi, FDAP fdap) AddPlace; - public function HResult(COM_IFileDialog* self, char16* pszDefaultExtension) SetDefaultExtension; - public function HResult(COM_IFileDialog* self, int hr) Close; - public function HResult(COM_IFileDialog* self, ref Guid guid) SetClientGuid; - public function HResult(COM_IFileDialog* self) ClearClientData; - public function HResult(COM_IFileDialog* self, void* pFilter) SetFilter; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, Windows.HWnd parent) Show; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, uint cFileTypes, COMDLG_FILTERSPEC* rgFilterSpec) SetFileTypes; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, uint iFileType) SetFileTypeIndex; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, out uint piFileType) GetFileTypeIndex; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, COM_IFileDialogEvents* pfde, out uint pdwCookie) Advise; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, uint dwCookie) Unadvise; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, FOS fos) SetOptions; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, out FOS pfos) GetOptions; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, COM_IShellItem* psi) SetDefaultFolder; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, COM_IShellItem* psi) SetFolder; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, out COM_IShellItem* ppsi) GetFolder; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, out COM_IShellItem* ppsi) GetCurrentSelection; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, char16* pszName) SetFileName; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, out char16* pszName) GetFileName; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, char16* pszTitle) SetTitle; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, char16* pszText) SetOkButtonLabel; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, char16* pszLabel) SetFileNameLabel; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, out COM_IShellItem* ppsi) GetResult; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, COM_IShellItem* psi, FDAP fdap) AddPlace; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, char16* pszDefaultExtension) SetDefaultExtension; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, int hr) Close; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, ref Guid guid) SetClientGuid; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self) ClearClientData; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileDialog* self, void* pFilter) SetFilter; } public new VTable* VT { @@ -1314,8 +1314,8 @@ namespace System public struct VTable : COM_IFileDialog.VTable { - public function HResult(COM_IFileOpenDialog* self, out COM_IShellItemArray* ppenum) GetResults; - public function HResult(COM_IFileOpenDialog* self, out COM_IShellItemArray* ppsai) GetSelectedItems; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileOpenDialog* self, out COM_IShellItemArray* ppenum) GetResults; + public function [CallingConvention(.Stdcall)] HResult(COM_IFileOpenDialog* self, out COM_IShellItemArray* ppsai) GetSelectedItems; } public new VTable* VT { diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 9bd0fa6f..21b546ba 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -14769,7 +14769,7 @@ BfAllocTarget BfExprEvaluator::ResolveAllocTarget(BfAstNode* allocNode, BfTokenN if (attributeDirective != NULL) { - auto customAttrs = mModule->GetCustomAttributes(attributeDirective, BfAttributeTargets_Alloc, true, &allocTarget.mCaptureInfo); + auto customAttrs = mModule->GetCustomAttributes(attributeDirective, BfAttributeTargets_Alloc, BfGetCustomAttributesFlags_AllowNonConstArgs, &allocTarget.mCaptureInfo); if (customAttrs != NULL) { for (auto& attrib : customAttrs->mAttributes) diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index d085677a..0468eeb1 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -11144,8 +11144,11 @@ void BfModule::ValidateCustomAttributes(BfCustomAttributes* customAttributes, Bf } } -void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeDirective* attributesDirective, BfAttributeTargets attrTarget, bool allowNonConstArgs, BfCaptureInfo* captureInfo) +void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeDirective* attributesDirective, BfAttributeTargets attrTarget, BfGetCustomAttributesFlags flags, BfCaptureInfo* captureInfo) { + bool allowNonConstArgs = (flags & BfGetCustomAttributesFlags_AllowNonConstArgs) != 0; + bool keepConstsInModule = (flags & BfGetCustomAttributesFlags_KeepConstsInModule) != 0; + if (!mCompiler->mHasRequiredTypes) return; @@ -11389,7 +11392,8 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri BfTypedValue result = constResolver.Resolve(assignExpr->mRight, fieldTypeInst.mResolvedType, BfConstResolveFlag_NoActualizeValues); if (result) { - CurrentAddToConstHolder(result.mValue); + if (!keepConstsInModule) + CurrentAddToConstHolder(result.mValue); setField.mParam = result; customAttribute.mSetField.push_back(setField); } @@ -11451,7 +11455,8 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri if (!result.mValue.IsConst()) result = GetDefaultTypedValue(result.mType); BF_ASSERT(result.mType == propType); - CurrentAddToConstHolder(result.mValue); + if (!keepConstsInModule) + CurrentAddToConstHolder(result.mValue); setProperty.mParam = result; customAttribute.mSetProperties.push_back(setProperty); } @@ -11567,10 +11572,13 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri } // Move all those to the constHolder - for (auto& ctorArg : customAttribute.mCtorArgs) - { - if (ctorArg.IsConst()) - CurrentAddToConstHolder(ctorArg); + if (!keepConstsInModule) + { + for (auto& ctorArg : customAttribute.mCtorArgs) + { + if (ctorArg.IsConst()) + CurrentAddToConstHolder(ctorArg); + } } if (attributesDirective->mAttributeTargetSpecifier != NULL) @@ -11627,10 +11635,10 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri ValidateCustomAttributes(customAttributes, attrTarget); } -BfCustomAttributes* BfModule::GetCustomAttributes(BfAttributeDirective* attributesDirective, BfAttributeTargets attrType, bool allowNonConstArgs, BfCaptureInfo* captureInfo) +BfCustomAttributes* BfModule::GetCustomAttributes(BfAttributeDirective* attributesDirective, BfAttributeTargets attrType, BfGetCustomAttributesFlags flags, BfCaptureInfo* captureInfo) { BfCustomAttributes* customAttributes = new BfCustomAttributes(); - GetCustomAttributes(customAttributes, attributesDirective, attrType, allowNonConstArgs, captureInfo); + GetCustomAttributes(customAttributes, attributesDirective, attrType, flags, captureInfo); return customAttributes; } @@ -15480,7 +15488,11 @@ void BfModule::CreateDelegateInvokeMethod() mBfIRBuilder->AddBlock(doneBB); mBfIRBuilder->SetInsertPoint(doneBB); - if ((mCurMethodInstance->mReturnType->IsValuelessType()) || + if (mCurMethodInstance->mReturnType->IsVar()) + { + // Do nothing + } + else if ((mCurMethodInstance->mReturnType->IsValuelessType()) || ((!mIsComptimeModule) && (mCurMethodInstance->GetStructRetIdx() != -1))) { mBfIRBuilder->CreateRetVoid(); @@ -21553,6 +21565,10 @@ void BfModule::GetMethodCustomAttributes(BfMethodInstance* methodInstance) } } } + + auto delegateInfo = typeInstance->GetDelegateInfo(); + if ((delegateInfo != NULL) && (methodInstance->mMethodDef->mMethodType == BfMethodType_Normal) && (methodInstance->mMethodDef->mName == "Invoke")) + methodInstance->mCallingConvention = delegateInfo->mCallingConvention; } void BfModule::SetupIRFunction(BfMethodInstance* methodInstance, StringImpl& mangledName, bool isTemporaryFunc, bool* outIsIntrinsic) @@ -21831,6 +21847,11 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool { BP_ZONE("BfModule::BfMethodDeclaration"); + if (mCurTypeInstance->IsFunctionFromTypeRef()) + { + NOP; + } + // We could trigger a DoMethodDeclaration from a const resolver or other location, so we reset it here // to effectively make mIgnoreWrites method-scoped SetAndRestoreValue prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, mWantsIRIgnoreWrites || mCurMethodInstance->mIsUnspecialized || mCurTypeInstance->mResolvingVarField); diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index d575d265..0be8a8b2 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -1383,6 +1383,13 @@ enum BfDeferredBlockFlags BfDeferredBlockFlag_MoveNewBlocksToEnd = 8, }; +enum BfGetCustomAttributesFlags +{ + BfGetCustomAttributesFlags_None = 0, + BfGetCustomAttributesFlags_AllowNonConstArgs = 1, + BfGetCustomAttributesFlags_KeepConstsInModule = 2 +}; + class BfVDataExtEntry { public: @@ -1567,8 +1574,8 @@ public: BfTypedValue GetTypedValueFromConstant(BfConstant* constant, BfIRConstHolder* constHolder, BfType* wantType); BfIRValue ConstantToCurrent(BfConstant* constant, BfIRConstHolder* constHolder, BfType* wantType, bool allowUnactualized = false); void ValidateCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeTargets attrTarget); - void GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeDirective* attributesDirective, BfAttributeTargets attrType, bool allowNonConstArgs = false, BfCaptureInfo* captureInfo = NULL); - BfCustomAttributes* GetCustomAttributes(BfAttributeDirective* attributesDirective, BfAttributeTargets attrType, bool allowNonConstArgs = false, BfCaptureInfo* captureInfo = NULL); + void GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeDirective* attributesDirective, BfAttributeTargets attrType, BfGetCustomAttributesFlags flags = BfGetCustomAttributesFlags_None, BfCaptureInfo* captureInfo = NULL); + BfCustomAttributes* GetCustomAttributes(BfAttributeDirective* attributesDirective, BfAttributeTargets attrType, BfGetCustomAttributesFlags flags = BfGetCustomAttributesFlags_None, BfCaptureInfo* captureInfo = NULL); BfCustomAttributes* GetCustomAttributes(BfTypeDef* typeDef); void FinishAttributeState(BfAttributeState* attributeState); void ProcessTypeInstCustomAttributes(bool& isPacked, bool& isUnion, bool& isCRepr, bool& isOrdered, int& alignOverride, BfType*& underlyingArrayType, int& underlyingArraySize); @@ -1846,6 +1853,7 @@ public: void CheckIdentifierFixit(BfAstNode* node); void TypeRefNotFound(BfTypeReference* typeRef, const char* appendName = NULL); bool ValidateTypeWildcard(BfTypeReference* typeRef, bool isAttributeRef); + void GetDelegateTypeRefAttributes(BfDelegateTypeRef* delegateTypeRef, BfCallingConvention& callingConvention); BfType* ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType populateType = BfPopulateType_Data, BfResolveTypeRefFlags resolveFlags = (BfResolveTypeRefFlags)0, int numGenericArgs = 0); BfType* ResolveTypeRefAllowUnboundGenerics(BfTypeReference* typeRef, BfPopulateType populateType = BfPopulateType_Data, bool resolveGenericParam = true); BfType* ResolveTypeRef(BfAstNode* astNode, const BfSizedArray* genericArgs, BfPopulateType populateType = BfPopulateType_Data, BfResolveTypeRefFlags resolveFlags = (BfResolveTypeRefFlags)0); diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index d1201234..616b3c45 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -9370,6 +9370,28 @@ BfTypedValue BfModule::TryLookupGenericConstVaue(BfIdentifierNode* identifierNod return BfTypedValue(); } +void BfModule::GetDelegateTypeRefAttributes(BfDelegateTypeRef* delegateTypeRef, BfCallingConvention& callingConvention) +{ + if (delegateTypeRef->mAttributes == NULL) + return; + + BfCaptureInfo captureInfo; + auto customAttributes = GetCustomAttributes(delegateTypeRef->mAttributes, (BfAttributeTargets)(BfAttributeTargets_DelegateTypeRef | BfAttributeTargets_FunctionTypeRef), BfGetCustomAttributesFlags_KeepConstsInModule); + if (customAttributes != NULL) + { + auto linkNameAttr = customAttributes->Get(mCompiler->mCallingConventionAttributeTypeDef); + if (linkNameAttr != NULL) + { + if (linkNameAttr->mCtorArgs.size() == 1) + { + auto constant = mBfIRBuilder->GetConstant(linkNameAttr->mCtorArgs[0]); + if (constant != NULL) + callingConvention = (BfCallingConvention)constant->mInt32; + } + } + } +} + BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType populateType, BfResolveTypeRefFlags resolveFlags, int numGenericArgs) { BP_ZONE("BfModule::ResolveTypeRef"); @@ -10113,6 +10135,9 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula lookupCtx.mRootTypeDef = typeDef; lookupCtx.mModule = this; BfResolvedTypeSet::Entry* resolvedEntry = NULL; + if (auto delegateTypeRef = BfNodeDynCastExact(typeRef)) + GetDelegateTypeRefAttributes(delegateTypeRef, lookupCtx.mCallingConvention); + auto inserted = mContext->mResolvedTypes.Insert(typeRef, &lookupCtx, &resolvedEntry); if (resolvedEntry == NULL) @@ -10867,7 +10892,9 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula dlgType->mIsUnspecializedTypeVariation = isUnspecialized; delegateType = dlgType; } - + + delegateInfo->mCallingConvention = lookupCtx.mCallingConvention; + Val128 hashContext; BfTypeDef* typeDef = new BfTypeDef(); @@ -13123,9 +13150,11 @@ BfTypedValue BfModule::Cast(BfAstNode* srcNode, const BfTypedValue& typedVal, Bf auto fromMethodInst = GetRawMethodByName(fromTypeInst, "Invoke", -1, true); auto toMethodInst = GetRawMethodByName(toTypeInst, "Invoke", -1, true); - + + auto toDelegateInfo = toTypeInst->GetDelegateInfo(); + if ((fromMethodInst != NULL) && (toMethodInst != NULL) && - (fromMethodInst->mMethodDef->mCallingConvention == toMethodInst->mMethodDef->mCallingConvention) && + (fromMethodInst->mCallingConvention == toMethodInst->mCallingConvention) && (fromMethodInst->mMethodDef->mIsMutating == toMethodInst->mMethodDef->mIsMutating) && (fromMethodInst->mReturnType == toMethodInst->mReturnType) && (fromMethodInst->GetParamCount() == toMethodInst->GetParamCount())) @@ -13706,6 +13735,25 @@ void BfModule::DoTypeToString(StringImpl& str, BfType* resolvedType, BfTypeNameF str += "delegate "; else str += "function "; + + if (delegateInfo->mCallingConvention != BfCallingConvention_Unspecified) + { + str += "[CallingConvention("; + switch (delegateInfo->mCallingConvention) + { + case BfCallingConvention_Cdecl: + str += ".Cdecl"; + break; + case BfCallingConvention_Stdcall: + str += ".Stdcall"; + break; + case BfCallingConvention_Fastcall: + str += ".Fastcall"; + break; + } + str += ")] "; + } + DoTypeToString(str, delegateInfo->mReturnType, typeNameFlags, genericMethodNameOverrides); str += "("; diff --git a/IDEHelper/Compiler/BfPrinter.cpp b/IDEHelper/Compiler/BfPrinter.cpp index a5e473df..39dcbbce 100644 --- a/IDEHelper/Compiler/BfPrinter.cpp +++ b/IDEHelper/Compiler/BfPrinter.cpp @@ -1585,8 +1585,9 @@ void BfPrinter::Visit(BfDelegateTypeRef* typeRef) VisitChild(typeRef->mTypeToken); ExpectSpace(); - VisitChild(typeRef->mReturnType); VisitChild(typeRef->mAttributes); + ExpectSpace(); + VisitChild(typeRef->mReturnType); VisitChild(typeRef->mOpenParen); for (int i = 0; i < (int)typeRef->mParams.size(); i++) diff --git a/IDEHelper/Compiler/BfReducer.cpp b/IDEHelper/Compiler/BfReducer.cpp index baa65d07..0164aad0 100644 --- a/IDEHelper/Compiler/BfReducer.cpp +++ b/IDEHelper/Compiler/BfReducer.cpp @@ -281,9 +281,52 @@ bool BfReducer::IsTypeReference(BfAstNode* checkNode, BfToken successToken, int* int endNode = -1; + bool failed = false; + // Return type auto checkNode = mVisitorPos.GetCurrent(); - if ((checkNode == NULL) || (!IsTypeReference(checkNode, BfToken_LParen, &endNode, couldBeExpr, isGenericType, isTuple))) + if (auto checkToken = BfNodeDynCast(checkNode)) + { + if (checkToken->mToken == BfToken_LBracket) + { + while (true) + { + mVisitorPos.mReadPos++; + checkNode = mVisitorPos.GetCurrent(); + if (checkNode == NULL) + { + failed = true; + break; + } + + if (BfNodeIsA(checkNode)) + { + failed = true; + break; + } + + if (checkToken = BfNodeDynCast(checkNode)) + { + if (checkToken->mToken == BfToken_RBracket) + { + mVisitorPos.mReadPos++; + checkNode = mVisitorPos.GetCurrent(); + break; + } + if ((checkToken->mToken != BfToken_Comma) && + (checkToken->mToken != BfToken_Dot) && + (checkToken->mToken != BfToken_LParen) && + (checkToken->mToken != BfToken_RParen)) + { + failed = true; + break; + } + } + } + } + } + + if ((failed) || (checkNode == NULL) || (!IsTypeReference(checkNode, BfToken_LParen, &endNode, couldBeExpr, isGenericType, isTuple))) { if (outEndNode != NULL) *outEndNode = endNode; @@ -4806,6 +4849,14 @@ BfTypeReference* BfReducer::DoCreateTypeRef(BfAstNode* firstNode, CreateTypeRefF ReplaceNode(firstNode, delegateTypeRef); MEMBER_SET(delegateTypeRef, mTypeToken, tokenNode); + auto nextToken = BfNodeDynCast(mVisitorPos.GetNext()); + if ((nextToken != NULL) && (nextToken->mToken == BfToken_LBracket)) + { + mVisitorPos.MoveNext(); + auto attribs = CreateAttributeDirective(nextToken); + MEMBER_SET_CHECKED(delegateTypeRef, mAttributes, attribs); + } + auto returnType = CreateTypeRefAfter(delegateTypeRef); MEMBER_SET_CHECKED(delegateTypeRef, mReturnType, returnType); diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp index 3e4e49f2..712a7ec5 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp @@ -3670,6 +3670,8 @@ bool BfResolvedTypeSet::Equals(BfType* lhs, BfType* rhs, LookupContext* ctx) BfDelegateInfo* rhsDelegateInfo = rhs->GetDelegateInfo(); if (lhsInst->mTypeDef->mIsDelegate != rhsInst->mTypeDef->mIsDelegate) return false; + if (lhsDelegateInfo->mCallingConvention != rhsDelegateInfo->mCallingConvention) + return false; auto lhsMethodDef = lhsInst->mTypeDef->mMethods[0]; auto rhsMethodDef = rhsInst->mTypeDef->mMethods[0]; @@ -4091,8 +4093,16 @@ bool BfResolvedTypeSet::Equals(BfType* lhs, BfTypeReference* rhs, LookupContext* if ((lhs->IsDelegate()) != rhsIsDelegate) return false; + + BfCallingConvention rhsCallingConvention = BfCallingConvention_Unspecified; + if (ctx->mRootTypeRef == rhsDelegateType) + rhsCallingConvention = ctx->mCallingConvention; + else + ctx->mModule->GetDelegateTypeRefAttributes(rhsDelegateType, rhsCallingConvention); + if (lhsDelegateInfo->mCallingConvention != rhsCallingConvention) + return false; if (!Equals(lhsDelegateInfo->mReturnType, rhsDelegateType->mReturnType, ctx)) - return false; + return false; bool isMutating = true; diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index f02f097c..cd59cf14 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -452,6 +452,7 @@ public: Array mParams; bool mHasExplicitThis; bool mHasVarArgs; + BfCallingConvention mCallingConvention; public: BfDelegateInfo() @@ -459,6 +460,7 @@ public: mReturnType = NULL; mHasExplicitThis = false; mHasVarArgs = false; + mCallingConvention = BfCallingConvention_Unspecified; } ~BfDelegateInfo() @@ -1582,7 +1584,9 @@ enum BfAttributeTargets : int32 BfAttributeTargets_Delete = 0x80000, BfAttributeTargets_Alias = 0x100000, BfAttributeTargets_Block = 0x200000, - BfAttributeTargets_All = 0x3FFFFF + BfAttributeTargets_DelegateTypeRef = 0x400000, + BfAttributeTargets_FunctionTypeRef = 0x800000, + BfAttributeTargets_All = 0xFFFFFF }; enum BfAttributeFlags : int8 @@ -2510,6 +2514,7 @@ public: BfType* mRootResolvedType; Dictionary mResolvedTypeMap; BfResolveTypeRefFlags mResolveFlags; + BfCallingConvention mCallingConvention; bool mHadVar; bool mFailed; @@ -2524,6 +2529,7 @@ public: mFailed = false; mHadVar = false; mResolveFlags = BfResolveTypeRefFlag_None; + mCallingConvention = BfCallingConvention_Unspecified; } BfType* GetCachedResolvedType(BfTypeReference* typeReference); From d40ddc0e6994f2646a3676ea661561187363fdfd Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 27 Dec 2021 13:14:17 -0500 Subject: [PATCH 120/139] Added EnumCase field flag --- BeefLibs/corlib/src/Type.bf | 3 ++- IDEHelper/Compiler/BfModule.cpp | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/BeefLibs/corlib/src/Type.bf b/BeefLibs/corlib/src/Type.bf index 1f79729b..ff17e330 100644 --- a/BeefLibs/corlib/src/Type.bf +++ b/BeefLibs/corlib/src/Type.bf @@ -1250,7 +1250,8 @@ namespace System.Reflection Const = 0x0040, // Value is compile time constant. SpecialName = 0x0080, // field is special. Name describes how. EnumPayload = 0x0100, - EnumDiscriminator = 0x0200 + EnumDiscriminator = 0x0200, + EnumFlags = 0x0400 } public enum MethodFlags : uint16 diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 0468eeb1..78a5e0e8 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -6368,7 +6368,8 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary& usedStrin FieldFlags_Const = 0x40, FieldFlags_SpecialName = 0x80, FieldFlags_EnumPayload = 0x100, - FieldFlags_EnumDiscriminator = 0x200 + FieldFlags_EnumDiscriminator = 0x200, + FieldFlags_EnumCase = 0x400 }; if ((typeInstance->IsPayloadEnum()) && (!typeInstance->IsBoxed())) @@ -6434,6 +6435,8 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary& usedStrin fieldFlags = (FieldFlags)(fieldFlags | FieldFlags_Static); if (fieldDef->mIsConst) fieldFlags = (FieldFlags)(fieldFlags | FieldFlags_Const); + if (fieldDef->IsEnumCaseEntry()) + fieldFlags = (FieldFlags)(fieldFlags | FieldFlags_EnumCase); int customAttrIdx = _HandleCustomAttrs(fieldInstance->mCustomAttributes); BfIRValue constValue; From 977772de083978b83edd56268c51ab9789a61721 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 27 Dec 2021 13:16:38 -0500 Subject: [PATCH 121/139] Fixed name --- BeefLibs/corlib/src/Type.bf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BeefLibs/corlib/src/Type.bf b/BeefLibs/corlib/src/Type.bf index ff17e330..89bcb9c4 100644 --- a/BeefLibs/corlib/src/Type.bf +++ b/BeefLibs/corlib/src/Type.bf @@ -1251,7 +1251,7 @@ namespace System.Reflection SpecialName = 0x0080, // field is special. Name describes how. EnumPayload = 0x0100, EnumDiscriminator = 0x0200, - EnumFlags = 0x0400 + EnumCase = 0x0400 } public enum MethodFlags : uint16 From 268d7f7dba52a970ff80b103bccc3a1fdac4b057 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 27 Dec 2021 13:34:36 -0500 Subject: [PATCH 122/139] Fixed DoImplicitArgCapture with value composite member --- IDEHelper/Compiler/BfExprEvaluator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 41a9978a..e6e65a8f 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -11492,7 +11492,7 @@ BfTypedValue BfExprEvaluator::DoImplicitArgCapture(BfAstNode* refNode, BfMethodI return lookupVal; } } - if (paramType->IsComposite()) + if ((paramType->IsComposite()) && (methodRefTarget.IsAddr())) return BfTypedValue(mModule->mBfIRBuilder->CreateInBoundsGEP(methodRefTarget.mValue, 0, dataIdx), paramType, true); return BfTypedValue(mModule->ExtractValue(methodRefTarget, dataIdx), paramType); } From 9cbc63887304b61d07542457e357df776dad8482 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 27 Dec 2021 14:02:51 -0500 Subject: [PATCH 123/139] Properly dispose of variant result --- BeefLibs/corlib/src/Reflection/AttributeInfo.bf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/BeefLibs/corlib/src/Reflection/AttributeInfo.bf b/BeefLibs/corlib/src/Reflection/AttributeInfo.bf index 1e515ae9..0489904a 100644 --- a/BeefLibs/corlib/src/Reflection/AttributeInfo.bf +++ b/BeefLibs/corlib/src/Reflection/AttributeInfo.bf @@ -105,7 +105,8 @@ namespace System.Reflection argIdx++; } - methodInfo.Invoke(targetAttr, params args); + if (methodInfo.Invoke(targetAttr, params args) case .Ok(var val)) + val.Dispose(); return .Ok; } From 1d30beb2d288468270cb7e58eaa7361ed8abd689 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 27 Dec 2021 14:03:08 -0500 Subject: [PATCH 124/139] Add comment for SetDefinitionLocation change --- IDEHelper/Compiler/BfExprEvaluator.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 79b17e3f..423e6f12 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -4919,7 +4919,10 @@ BfTypedValue BfExprEvaluator::LookupField(BfAstNode* targetSrc, BfTypedValue tar if ((autoComplete != NULL) && (autoComplete->IsAutocompleteNode(targetSrc))) { if (autoComplete->mIsGetDefinition) + { + //NOTE: passing 'force=true' in here causes https://github.com/beefytech/Beef/issues/1064 autoComplete->SetDefinitionLocation(basePropDef->GetRefNode()); + } autoComplete->mDefProp = basePropDef; autoComplete->mDefType = baseTypeInst->mTypeDef; } From f0bd5ceea59ccb4ddd2912d113de361c82b6e919 Mon Sep 17 00:00:00 2001 From: disarray2077 <86157825+disarray2077@users.noreply.github.com> Date: Mon, 27 Dec 2021 16:06:05 -0300 Subject: [PATCH 125/139] Fix enum fields enumerator --- BeefLibs/corlib/src/Enum.bf | 76 ++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 31 deletions(-) diff --git a/BeefLibs/corlib/src/Enum.bf b/BeefLibs/corlib/src/Enum.bf index 1137494e..33b04902 100644 --- a/BeefLibs/corlib/src/Enum.bf +++ b/BeefLibs/corlib/src/Enum.bf @@ -55,49 +55,63 @@ namespace System return .(); } - private struct EnumFieldsEnumeratorWrapper + private struct EnumFieldsEnumerator where TEnum : enum { - FieldInfo.Enumerator mEnumerator; + TypeInstance mTypeInstance; + int32 mIdx; public this() { - mEnumerator = typeof(TEnum).GetFields(); + mTypeInstance = typeof(TEnum) as TypeInstance; + mIdx = -1; } - public int Index + public void Reset() mut { - get - { - return mEnumerator.Index; - } - } - - public int Count - { - get - { - return mEnumerator.mTypeInstance.[Friend]mFieldDataCount; - } - } - - public FieldInfo Current - { - get - { - return (.)mEnumerator.Current; - } - } - - public bool MoveNext() mut - { - return mEnumerator.MoveNext(); + mIdx = -1; } public void Dispose() { } + public bool MoveNext() mut + { + if (mTypeInstance == null) + return false; + + TypeInstance.FieldData* fieldData = null; + + repeat + { + mIdx++; + if (mIdx == mTypeInstance.[Friend]mFieldDataCount) + return false; + fieldData = &mTypeInstance.[Friend]mFieldDataPtr[mIdx]; + } + while (!fieldData.mFlags.HasFlag(.EnumCase)); + + return true; + } + + public FieldInfo Current + { + get + { + var fieldData = &mTypeInstance.[Friend]mFieldDataPtr[mIdx]; + return FieldInfo(mTypeInstance, fieldData); + } + } + + public int32 Index + { + get + { + return mIdx; + } + } + public Result GetNext() mut { if (!MoveNext()) @@ -106,7 +120,7 @@ namespace System } } - public struct EnumValuesEnumerator : EnumFieldsEnumeratorWrapper, IEnumerator + public struct EnumValuesEnumerator : EnumFieldsEnumerator, IEnumerator where TEnum : enum { public new TEnum Current @@ -125,7 +139,7 @@ namespace System } } - public struct EnumNamesEnumerator : EnumFieldsEnumeratorWrapper, IEnumerator + public struct EnumNamesEnumerator : EnumFieldsEnumerator, IEnumerator where TEnum : enum { public new StringView Current From b57ac935e5cd8b2ffefcc2e750417a3913f8485c Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 27 Dec 2021 14:25:34 -0500 Subject: [PATCH 126/139] Add "Time Autocomplete" internal IDE flag --- IDE/src/Compiler/BfParser.bf | 1 + IDE/src/IDEApp.bf | 2 ++ IDE/src/ui/AutoComplete.bf | 1 + IDE/src/ui/SourceViewPanel.bf | 9 +++++++++ 4 files changed, 13 insertions(+) diff --git a/IDE/src/Compiler/BfParser.bf b/IDE/src/Compiler/BfParser.bf index dfb0d967..15ab5174 100644 --- a/IDE/src/Compiler/BfParser.bf +++ b/IDE/src/Compiler/BfParser.bf @@ -78,6 +78,7 @@ namespace IDE.Compiler public bool mCancelled; public int32 mTextVersion = -1; public bool mIsUserRequested; + public Stopwatch mStopwatch ~ delete _; } public class BfParser : ILeakIdentifiable diff --git a/IDE/src/IDEApp.bf b/IDE/src/IDEApp.bf index 51d9d475..8150ebb7 100644 --- a/IDE/src/IDEApp.bf +++ b/IDE/src/IDEApp.bf @@ -169,6 +169,7 @@ namespace IDE public bool mLastCompileHadMessages; public bool mPauseOnExit; public bool mDbgDelayedAutocomplete; + public bool mDbgTimeAutocomplete; public BeefConfig mBeefConfig = new BeefConfig() ~ delete _; public List mDeferredFails = new .() ~ DeleteContainerAndItems!(_); public String mInitialCWD = new .() ~ delete _; @@ -5429,6 +5430,7 @@ namespace IDE var internalEditMenu = subMenu.AddMenuItem("Internal"); internalEditMenu.AddMenuItem("Hilight Cursor References", null, new (menu) => { ToggleCheck(menu, ref gApp.mSettings.mEditorSettings.mHiliteCursorReferences); }, null, null, true, gApp.mSettings.mEditorSettings.mHiliteCursorReferences ? 1 : 0); internalEditMenu.AddMenuItem("Delayed Autocomplete", null, new (menu) => { ToggleCheck(menu, ref gApp.mDbgDelayedAutocomplete); }, null, null, true, gApp.mDbgDelayedAutocomplete ? 1 : 0); + internalEditMenu.AddMenuItem("Time Autocomplete", null, new (menu) => { ToggleCheck(menu, ref gApp.mDbgTimeAutocomplete); }, null, null, true, gApp.mDbgTimeAutocomplete ? 1 : 0); } ////////// diff --git a/IDE/src/ui/AutoComplete.bf b/IDE/src/ui/AutoComplete.bf index 1e0a4640..88fb6d2f 100644 --- a/IDE/src/ui/AutoComplete.bf +++ b/IDE/src/ui/AutoComplete.bf @@ -1128,6 +1128,7 @@ namespace IDE.ui } } + public Stopwatch mStopwatch ~ delete _; public EditWidget mTargetEditWidget; public Event mOnAutoCompleteInserted ~ _.Dispose(); public Event mOnClosed ~ _.Dispose(); diff --git a/IDE/src/ui/SourceViewPanel.bf b/IDE/src/ui/SourceViewPanel.bf index e3867de8..29441252 100644 --- a/IDE/src/ui/SourceViewPanel.bf +++ b/IDE/src/ui/SourceViewPanel.bf @@ -618,6 +618,8 @@ namespace IDE.ui //Classify(options.HasFlag(.HighPriority) ? ResolveType.Autocomplete_HighPri : ResolveType.Autocomplete); ResolveParams resolveParams = new ResolveParams(); + if (gApp.mDbgTimeAutocomplete) + resolveParams.mStopwatch = new .()..Start(); resolveParams.mIsUserRequested = options.HasFlag(.UserRequested); Classify(.Autocomplete, resolveParams); if (!resolveParams.mInDeferredList) @@ -5540,6 +5542,13 @@ namespace IDE.ui HandleResolveResult(resolveResult.mResolveType, resolveResult.mAutocompleteInfo, resolveResult); + if (resolveResult.mStopwatch != null) + { + resolveResult.mStopwatch.Stop(); + if (var autoComplete = GetAutoComplete()) + Debug.WriteLine($"Autocomplete {resolveResult.mStopwatch.ElapsedMilliseconds}ms entries: {autoComplete.mAutoCompleteListWidget.mEntryList.Count}"); + } + //Debug.WriteLine("ProcessDeferredResolveResults finished {0}", resolveResult.mResolveType); //bool checkIt = (mFilePath.Contains("Program.bf")) && (mEditWidget.mEditWidgetContent.mData.mCurTextVersionId > 3); From b2cb8f74d3909dd9cdf25ab87f6bdfc163dbd6cb Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 27 Dec 2021 14:34:55 -0500 Subject: [PATCH 127/139] Added GetEnumerator --- BeefLibs/corlib/src/Enum.bf | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/BeefLibs/corlib/src/Enum.bf b/BeefLibs/corlib/src/Enum.bf index 33b04902..31481a55 100644 --- a/BeefLibs/corlib/src/Enum.bf +++ b/BeefLibs/corlib/src/Enum.bf @@ -1,4 +1,5 @@ using System.Reflection; +using System.Collections; namespace System { @@ -43,13 +44,19 @@ namespace System return false; } - public static readonly EnumValuesEnumerator GetValues() + public static EnumEnumerator GetEnumerator() + where TEnum : enum + { + return .(); + } + + public static EnumValuesEnumerator GetValues() where TEnum : enum { return .(); } - public static readonly EnumNamesEnumerator GetNames() + public static EnumNamesEnumerator GetNames() where TEnum : enum { return .(); @@ -120,6 +127,25 @@ namespace System } } + public struct EnumEnumerator : EnumFieldsEnumerator, IEnumerator<(StringView name, TEnum value)> + where TEnum : enum + { + public new (StringView name, TEnum value) Current + { + get + { + return ((.)base.Current.[Friend]mFieldData.[Friend]mName, (.)base.Current.[Friend]mFieldData.[Friend]mData); + } + } + + public new Result<(StringView name, TEnum value)> GetNext() mut + { + if (!MoveNext()) + return .Err; + return Current; + } + } + public struct EnumValuesEnumerator : EnumFieldsEnumerator, IEnumerator where TEnum : enum { From 87ab0ad16905980112e1d3f2e6a75dd7058cc7a3 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 27 Dec 2021 15:05:58 -0500 Subject: [PATCH 128/139] Added error for 'readonly' on methods with non-ref return --- IDEHelper/Compiler/BfExprEvaluator.cpp | 2 +- IDEHelper/Compiler/BfModule.cpp | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 423e6f12..16b1a132 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -5410,7 +5410,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance* return result; } else - { + { auto val = mModule->GetDefaultTypedValue(returnType, true, (GetStructRetIdx(methodInstance) != -1) ? BfDefaultValueKind_Addr : BfDefaultValueKind_Value); if (val.mKind == BfTypedValueKind_Addr) val.mKind = BfTypedValueKind_RestrictedTempAddr; diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 78a5e0e8..86c767d4 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -21850,11 +21850,6 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool { BP_ZONE("BfModule::BfMethodDeclaration"); - if (mCurTypeInstance->IsFunctionFromTypeRef()) - { - NOP; - } - // We could trigger a DoMethodDeclaration from a const resolver or other location, so we reset it here // to effectively make mIgnoreWrites method-scoped SetAndRestoreValue prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, mWantsIRIgnoreWrites || mCurMethodInstance->mIsUnspecialized || mCurTypeInstance->mResolvingVarField); @@ -22187,6 +22182,13 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool if (resolvedReturnType == NULL) resolvedReturnType = GetPrimitiveType(BfTypeCode_Var); + + if ((methodDef->mIsReadOnly) && (!resolvedReturnType->IsRef())) + { + if (auto methodDeclaration = BfNodeDynCast(methodInstance->mMethodDef->mMethodDeclaration)) + if (methodDeclaration->mReadOnlySpecifier != NULL) + Fail("Readonly specifier is only valid on 'ref' return types", methodDeclaration->mReadOnlySpecifier); + } } else { From e81c0d6dfa016bc14cb3ac0638cc21a6a0f4f297 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 27 Dec 2021 15:26:20 -0500 Subject: [PATCH 129/139] Fixed a splat-to-addr bug with methodRef captures --- IDEHelper/Compiler/BfExprEvaluator.cpp | 4 ++++ IDEHelper/Tests/src/FuncRefs.bf | 31 ++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 16b1a132..794c2241 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -7116,7 +7116,11 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu if (methodRefType->WantsDataPassedAsSplat(dataIdx)) SplatArgs(lookupVal, irArgs); else + { + if (lookupVal.mType->IsComposite()) + lookupVal = mModule->MakeAddressable(lookupVal, false); irArgs.push_back(lookupVal.mValue); + } } } diff --git a/IDEHelper/Tests/src/FuncRefs.bf b/IDEHelper/Tests/src/FuncRefs.bf index d30e8216..0a5969d0 100644 --- a/IDEHelper/Tests/src/FuncRefs.bf +++ b/IDEHelper/Tests/src/FuncRefs.bf @@ -65,6 +65,34 @@ namespace Tests ac(); } + struct Vector2 : this(float x, float y) + { + } + + class TestA + { + Vector2 mVec = .(11, 22); + + public Vector2 Vec + { + set + { + DoIt(() => + { + Test.Assert(mVec.x == 11); + Test.Assert(mVec.y == 22); + Test.Assert(value.x == 33); + Test.Assert(value.y == 44); + }); + } + } + + public void DoIt(TDlg dlg) where TDlg : delegate void() + { + dlg(); + } + } + [Test] public static void TestBasics() { @@ -90,6 +118,9 @@ namespace Tests int a = 222; TestWrap(() => { a += 100; }); Test.Assert(a == 322); + + TestA ta = scope .(); + ta.Vec = .(33, 44); } struct MethodRefHolder where T : delegate int(int num) From 98eb8f5840d936425563cbc73cd9cb0dfbd93c90 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 28 Dec 2021 06:03:52 -0500 Subject: [PATCH 130/139] Fixed field dependency on methodRefs --- IDEHelper/Compiler/BfModuleTypeUtils.cpp | 18 ++++-------------- IDEHelper/Compiler/BfResolvedTypeUtils.cpp | 2 ++ 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 616b3c45..21ac3a07 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -704,23 +704,13 @@ void BfModule::InitType(BfType* resolvedTypeRef, BfPopulateType populateType) void BfModule::AddFieldDependency(BfTypeInstance* typeInstance, BfFieldInstance* fieldInstance, BfType* fieldType) { - auto fieldTypeInstance = fieldType->ToTypeInstance(); + auto depFlag = fieldType->IsValueType() ? BfDependencyMap::DependencyFlag_ValueTypeMemberData : BfDependencyMap::DependencyFlag_PtrMemberData; + AddDependency(fieldType, typeInstance, depFlag); - if (fieldTypeInstance == NULL) - { - auto underlyingType = fieldType->GetUnderlyingType(); - if (underlyingType != NULL) - AddFieldDependency(typeInstance, fieldInstance, underlyingType); - return; - } - - auto depFlag = fieldTypeInstance->IsValueType() ? BfDependencyMap::DependencyFlag_ValueTypeMemberData : BfDependencyMap::DependencyFlag_PtrMemberData; - AddDependency(fieldTypeInstance, typeInstance, depFlag); - - if ((fieldTypeInstance->IsStruct()) && (fieldTypeInstance->IsGenericTypeInstance())) + if ((fieldType->IsStruct()) && (fieldType->IsGenericTypeInstance())) { // When we're a generic struct, our data layout can depend on our generic parameters as well - auto genericTypeInstance = (BfTypeInstance*)fieldTypeInstance; + auto genericTypeInstance = (BfTypeInstance*)fieldType; for (auto typeGenericArg : genericTypeInstance->mGenericTypeInfo->mTypeGenericArguments) AddFieldDependency(typeInstance, fieldInstance, typeGenericArg); } diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp index 712a7ec5..2512e290 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp @@ -2664,6 +2664,8 @@ int BfArrayType::GetLengthBitCount() int BfMethodRefType::GetCaptureDataCount() { + if (mMethodRef == NULL) + return 0; return (int)mDataToParamIdx.size(); } From fd8e2dd2327a6e48b015d07995f6ca4a11057d46 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 28 Dec 2021 06:08:06 -0500 Subject: [PATCH 131/139] Fixed methodRef bindResult value type --- IDEHelper/Compiler/BfExprEvaluator.cpp | 4 ++-- IDEHelper/Compiler/BfIRBuilder.cpp | 2 ++ IDEHelper/Tests/src/FuncRefs.bf | 23 +++++++++++++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 794c2241..b5e621b4 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -11957,8 +11957,8 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr) if (bindResult.mTarget.IsSplat()) target = mModule->AggregateSplat(bindResult.mTarget, &bindResult.mIRArgs[0]); else - target = mModule->LoadValue(bindResult.mTarget); - + target = bindResult.mTarget; + mModule->mBfIRBuilder->CreateStore(target.mValue, elemPtr); mResult = BfTypedValue(methodRefPtr, methodRefType, true); diff --git a/IDEHelper/Compiler/BfIRBuilder.cpp b/IDEHelper/Compiler/BfIRBuilder.cpp index 57c74d92..701a3a75 100644 --- a/IDEHelper/Compiler/BfIRBuilder.cpp +++ b/IDEHelper/Compiler/BfIRBuilder.cpp @@ -2631,6 +2631,8 @@ void BfIRBuilder::CreateTypeDeclaration(BfType* type, bool forceDbgDefine) if (methodInstance != NULL) name += BfTypeUtils::HashEncode64(methodInstance->mIdHash).c_str(); + BF_ASSERT(methodInstance != NULL); + if ((wantDIData) && (methodInstance != NULL)) { auto typeDeclaration = methodInstance->GetOwner()->mTypeDef->mTypeDeclaration; diff --git a/IDEHelper/Tests/src/FuncRefs.bf b/IDEHelper/Tests/src/FuncRefs.bf index 0a5969d0..76dedf7c 100644 --- a/IDEHelper/Tests/src/FuncRefs.bf +++ b/IDEHelper/Tests/src/FuncRefs.bf @@ -69,9 +69,21 @@ namespace Tests { } + class Invoker + { + public int mA = 111; + + public void Invoke() + { + mA += 222; + } + } + class TestA { Vector2 mVec = .(11, 22); + Event mEvt ~ _.Dispose(); + Action mAct; public Vector2 Vec { @@ -84,6 +96,17 @@ namespace Tests Test.Assert(value.x == 33); Test.Assert(value.y == 44); }); + Invoker invoker = scope .(); + mEvt.Add(new => invoker); + DoIt(=> mEvt); + Test.Assert(invoker.mA == 333); + DoIt(=> invoker); + Test.Assert(invoker.mA == 555); + mAct = scope => invoker; + mAct(); + Test.Assert(invoker.mA == 777); + DoIt(=> mAct); + Test.Assert(invoker.mA == 999); } } From 8c086eb7ef245f4bf4fa114ae9859f637a738b8e Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 28 Dec 2021 08:29:45 -0500 Subject: [PATCH 132/139] Fixed Stop Debugging with tests, added Perf Autocomplete --- IDE/src/IDEApp.bf | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/IDE/src/IDEApp.bf b/IDE/src/IDEApp.bf index 8150ebb7..3cdca790 100644 --- a/IDE/src/IDEApp.bf +++ b/IDE/src/IDEApp.bf @@ -170,6 +170,7 @@ namespace IDE public bool mPauseOnExit; public bool mDbgDelayedAutocomplete; public bool mDbgTimeAutocomplete; + public bool mDbgPerfAutocomplete; public BeefConfig mBeefConfig = new BeefConfig() ~ delete _; public List mDeferredFails = new .() ~ DeleteContainerAndItems!(_); public String mInitialCWD = new .() ~ delete _; @@ -5270,6 +5271,11 @@ namespace IDE menu.SetDisabled(!mDebugger.mIsRunning); } + public void UpdateMenuItem_DebugOrTestRunning(IMenu menu) + { + menu.SetDisabled(!mDebugger.mIsRunning && (mTestManager == null)); + } + public void UpdateMenuItem_DebugStopped_HasWorkspace(IMenu menu) { menu.SetDisabled(mDebugger.mIsRunning || !mWorkspace.IsInitialized); @@ -5431,6 +5437,7 @@ namespace IDE internalEditMenu.AddMenuItem("Hilight Cursor References", null, new (menu) => { ToggleCheck(menu, ref gApp.mSettings.mEditorSettings.mHiliteCursorReferences); }, null, null, true, gApp.mSettings.mEditorSettings.mHiliteCursorReferences ? 1 : 0); internalEditMenu.AddMenuItem("Delayed Autocomplete", null, new (menu) => { ToggleCheck(menu, ref gApp.mDbgDelayedAutocomplete); }, null, null, true, gApp.mDbgDelayedAutocomplete ? 1 : 0); internalEditMenu.AddMenuItem("Time Autocomplete", null, new (menu) => { ToggleCheck(menu, ref gApp.mDbgTimeAutocomplete); }, null, null, true, gApp.mDbgTimeAutocomplete ? 1 : 0); + internalEditMenu.AddMenuItem("Perf Autocomplete", null, new (menu) => { ToggleCheck(menu, ref gApp.mDbgPerfAutocomplete); }, null, null, true, gApp.mDbgPerfAutocomplete ? 1 : 0); } ////////// @@ -5490,7 +5497,7 @@ namespace IDE AddMenuItem(subMenu, "Start With&out Compiling", "Start Without Compiling", new => UpdateMenuItem_DebugStopped_HasWorkspace); AddMenuItem(subMenu, "&Launch Process...", "Launch Process", new => UpdateMenuItem_DebugStopped); AddMenuItem(subMenu, "&Attach to Process...", "Attach to Process", new => UpdateMenuItem_DebugStopped); - AddMenuItem(subMenu, "&Stop Debugging", "Stop Debugging", new => UpdateMenuItem_DebugRunning); + AddMenuItem(subMenu, "&Stop Debugging", "Stop Debugging", new => UpdateMenuItem_DebugOrTestRunning); AddMenuItem(subMenu, "Break All", "Break All", new => UpdateMenuItem_DebugNotPaused); AddMenuItem(subMenu, "Remove All Breakpoints", "Remove All Breakpoints"); AddMenuItem(subMenu, "Show &Disassembly", "Show Disassembly"); From 7c03f5e2cd4bff6cd07c958e0d89702c5faec258 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 28 Dec 2021 08:30:33 -0500 Subject: [PATCH 133/139] Added CPU usage to profiler thread list --- BeefLibs/corlib/src/Diagnostics/Profiler.bf | 13 +- IDE/src/Compiler/BfParser.bf | 1 + IDE/src/ui/ProfilePanel.bf | 34 ++++- IDE/src/ui/SourceViewPanel.bf | 2 + IDEHelper/Profiler.cpp | 143 +++++++++++++------- IDEHelper/Profiler.h | 6 +- 6 files changed, 139 insertions(+), 60 deletions(-) diff --git a/BeefLibs/corlib/src/Diagnostics/Profiler.bf b/BeefLibs/corlib/src/Diagnostics/Profiler.bf index f9fdbf54..f221cd70 100644 --- a/BeefLibs/corlib/src/Diagnostics/Profiler.bf +++ b/BeefLibs/corlib/src/Diagnostics/Profiler.bf @@ -10,12 +10,23 @@ namespace System.Diagnostics struct ProfileInstance : int32 { - public void Dispose() + public bool HasValue { + get + { + return this != 0; + } + } + + public void Dispose() mut + { + if (this == 0) + return; String str = scope String(); str.Append("StopSampling\t"); ((int32)this).ToString(str); Internal.ProfilerCmd(str); + this = 0; } } diff --git a/IDE/src/Compiler/BfParser.bf b/IDE/src/Compiler/BfParser.bf index 15ab5174..ae592597 100644 --- a/IDE/src/Compiler/BfParser.bf +++ b/IDE/src/Compiler/BfParser.bf @@ -79,6 +79,7 @@ namespace IDE.Compiler public int32 mTextVersion = -1; public bool mIsUserRequested; public Stopwatch mStopwatch ~ delete _; + public ProfileInstance mProfileInstance ~ _.Dispose(); } public class BfParser : ILeakIdentifiable diff --git a/IDE/src/ui/ProfilePanel.bf b/IDE/src/ui/ProfilePanel.bf index 2ca2beb8..033c553e 100644 --- a/IDE/src/ui/ProfilePanel.bf +++ b/IDE/src/ui/ProfilePanel.bf @@ -293,6 +293,10 @@ namespace IDE.ui } } + struct ThreadEntry : this(int32 mThreadId, int32 mCPUUsage, StringView mName) + { + } + void PopulateThreadList(Menu menu) { if (mProfiler == null) @@ -307,6 +311,7 @@ namespace IDE.ui var threadListStr = scope String(); mProfiler.GetThreadList(threadListStr); + List entries = scope .(); for (var entry in threadListStr.Split('\n')) { if (entry.Length == 0) @@ -314,20 +319,35 @@ namespace IDE.ui var dataItr = entry.Split('\t'); - int32 threadId = int32.Parse(dataItr.GetNext()); - StringView threadName = dataItr.GetNext(); + ThreadEntry threadEntry = default; + threadEntry.mThreadId = int32.Parse(dataItr.GetNext()); + threadEntry.mCPUUsage = int32.Parse(dataItr.GetNext()); + threadEntry.mName = dataItr.GetNext(); + entries.Add(threadEntry); + } + entries.Sort(scope (lhs, rhs) => + { + int cmp = rhs.mCPUUsage <=> lhs.mCPUUsage; + if (cmp == 0) + cmp = lhs.mThreadId <=> rhs.mThreadId; + return cmp; + }); + + for (var entry in entries) + { String threadStr = null; var str = scope String(); - str.AppendF("{0}", threadId); - if (!threadName.IsEmpty) + str.AppendF("{0}", entry.mThreadId); + str.AppendF($" ({entry.mCPUUsage}%)"); + if (!entry.mName.IsEmpty) { - threadStr = new String(threadName); - str.AppendF(" - {0}", threadName); + threadStr = new String(entry.mName); + str.AppendF($" - {entry.mName}"); } subItem = menu.AddItem(str); - subItem.mOnMenuItemSelected.Add(new (item) => { Show(threadId, threadStr); } ~ delete threadStr); + subItem.mOnMenuItemSelected.Add(new (item) => { Show(entry.mThreadId, threadStr); } ~ delete threadStr); } } diff --git a/IDE/src/ui/SourceViewPanel.bf b/IDE/src/ui/SourceViewPanel.bf index 29441252..8e75ddb1 100644 --- a/IDE/src/ui/SourceViewPanel.bf +++ b/IDE/src/ui/SourceViewPanel.bf @@ -620,6 +620,8 @@ namespace IDE.ui ResolveParams resolveParams = new ResolveParams(); if (gApp.mDbgTimeAutocomplete) resolveParams.mStopwatch = new .()..Start(); + if (gApp.mDbgPerfAutocomplete) + resolveParams.mProfileInstance = Profiler.StartSampling("Autocomplete").GetValueOrDefault(); resolveParams.mIsUserRequested = options.HasFlag(.UserRequested); Classify(.Autocomplete, resolveParams); if (!resolveParams.mInDeferredList) diff --git a/IDEHelper/Profiler.cpp b/IDEHelper/Profiler.cpp index 1cca8c3c..ba6e6c8b 100644 --- a/IDEHelper/Profiler.cpp +++ b/IDEHelper/Profiler.cpp @@ -8,12 +8,12 @@ typedef LONG KPRIORITY; USING_NS_BF_DBG; -enum SYSTEM_INFORMATION_CLASS +enum SYSTEM_INFORMATION_CLASS { SystemProcessInformation = 5 }; // SYSTEM_INFORMATION_CLASS -struct CLIENT_ID +struct CLIENT_ID { HANDLE UniqueProcess; HANDLE UniqueThread; @@ -81,14 +81,14 @@ struct SYSTEM_PROCESS_INFORMATION SYSTEM_THREAD Threads[1]; }; -typedef NTSTATUS(NTAPI *NtQuerySystemInformation_t)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG); +typedef NTSTATUS(NTAPI* NtQuerySystemInformation_t)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG); static NtQuerySystemInformation_t NtQuerySystemInformation = NULL; static HMODULE ntdll = NULL; DbgProfiler::DbgProfiler(WinDebugger* debugger) : mShutdownEvent(true) { mDebugger = debugger; - mIsRunning = false; + mIsRunning = false; mWantsClear = false; mSamplesPerSecond = 1000; @@ -101,6 +101,12 @@ DbgProfiler::DbgProfiler(WinDebugger* debugger) : mShutdownEvent(true) mEndTick = 0; mDebugger->AddProfiler(this); + + mIdleSymbolNames.Add("ZwDelayExecution"); + mIdleSymbolNames.Add("ZwWaitForWorkViaWorkerFactory"); + mIdleSymbolNames.Add("NtWaitForAlertByThreadId"); + mIdleSymbolNames.Add("NtWaitForSingleObject"); + mIdleSymbolNames.Add("NtWaitForMultipleObjects"); } DbgProfiler::~DbgProfiler() @@ -113,14 +119,14 @@ DbgProfiler::~DbgProfiler() } static SYSTEM_PROCESS_INFORMATION* CaptureProcessInfo() -{ +{ WCHAR path[MAX_PATH]; GetSystemDirectory(path, MAX_PATH); - wcscat(path, L"\\ntdll.dll"); - ntdll = GetModuleHandle(path); + wcscat(path, L"\\ntdll.dll"); + ntdll = GetModuleHandle(path); if (ntdll == NULL) return NULL; - NtQuerySystemInformation = (NtQuerySystemInformation_t)GetProcAddress(ntdll, "NtQuerySystemInformation"); + NtQuerySystemInformation = (NtQuerySystemInformation_t)GetProcAddress(ntdll, "NtQuerySystemInformation"); uint allocSize = 1024; uint8* data = NULL; @@ -134,7 +140,7 @@ static SYSTEM_PROCESS_INFORMATION* CaptureProcessInfo() if (status != STATUS_INFO_LENGTH_MISMATCH) return (SYSTEM_PROCESS_INFORMATION*)data; - + allocSize = wantSize + 4096; delete data; } @@ -148,8 +154,8 @@ void DbgProfiler::DoClear() delete val.mProcId; } -ProfileProcId* DbgProfiler::Get(const StringImpl& str) -{ +ProfileProcId* DbgProfiler::Get(const StringImpl& str, bool* outIsNew) +{ ProfileProdIdEntry checkEntry; checkEntry.mProcId = (ProfileProcId*)&str; @@ -158,11 +164,16 @@ ProfileProcId* DbgProfiler::Get(const StringImpl& str) { auto procId = new ProfileProcId(); procId->mProcName = str; - entryPtr->mProcId = procId; + procId->mIsIdle = false; + entryPtr->mProcId = procId; + if (outIsNew != NULL) + *outIsNew = true; return procId; } else { + if (outIsNew != NULL) + *outIsNew = false; return entryPtr->mProcId; } } @@ -170,7 +181,7 @@ ProfileProcId* DbgProfiler::Get(const StringImpl& str) void DbgProfiler::ThreadProc() { //TODO: Do timing smarter, handle delays and slow stack traces and stuff - + //timeBeginPeriod(1); BF_ASSERT(mTotalVirtualSamples == 0); @@ -184,7 +195,7 @@ void DbgProfiler::ThreadProc() uint32 accumMS = 0; int totalWait = 0; - int totalWait2 = 0; + int totalWait2 = 0; int iterations = 0; HashSet idleThreadSet; @@ -218,9 +229,11 @@ void DbgProfiler::ThreadProc() iterations++; DWORD startTick0 = timeGetTime(); idleThreadSet.Clear(); - + SYSTEM_PROCESS_INFORMATION* processData = NULL; - std::unique_ptr ptrDelete(processData); + std::unique_ptr ptrDelete(processData); + + //processData = CaptureProcessInfo(); auto curProcessData = processData; while (true) @@ -235,6 +248,7 @@ void DbgProfiler::ThreadProc() auto& threadInfo = curProcessData->Threads[threadIdx]; if ((threadInfo.State == StateWait) || (threadInfo.State == StateTerminated)) idleThreadSet.Add((int)(intptr)threadInfo.ClientId.UniqueThread); + break; } } @@ -242,12 +256,12 @@ void DbgProfiler::ThreadProc() break; curProcessData = (SYSTEM_PROCESS_INFORMATION*)((intptr)curProcessData + curProcessData->NextEntryOffset); } - + if (mShutdownEvent.WaitFor(0)) { break; } - + DWORD tickNow = timeGetTime(); accumMS += (int)(tickNow - prevSampleTick); prevSampleTick = tickNow; @@ -284,21 +298,21 @@ void DbgProfiler::ThreadProc() mTotalVirtualSamples += curSampleCount; mTotalActualSamples++; - + int threadIdx = 0; while (true) - { + { int startTick = timeGetTime(); - AutoCrit autoCrit(mDebugger->mDebugManager->mCritSect); - - if (mDebugger->mRunState != RunState_Running) - break; + AutoCrit autoCrit(mDebugger->mDebugManager->mCritSect); + + if (mDebugger->mRunState != RunState_Running) + break; if (threadIdx >= mDebugger->mThreadList.size()) break; - auto thread = mDebugger->mThreadList[threadIdx]; + auto thread = mDebugger->mThreadList[threadIdx]; if ((mTargetThreadId > 0) && (thread->mThreadId != mTargetThreadId)) { @@ -321,20 +335,22 @@ void DbgProfiler::ThreadProc() profileThreadInfo = *profileThreadInfoPtr; } - profileThreadInfo->mTotalSamples += curSampleCount; - bool isThreadIdle = idleThreadSet.Contains(thread->mThreadId); + profileThreadInfo->mTotalSamples += curSampleCount; + if (isThreadIdle) + profileThreadInfo->mTotalIdleSamples += curSampleCount; + mDebugger->mActiveThread = thread; - - ::SuspendThread(thread->mHThread); + + ::SuspendThread(thread->mHThread); CPURegisters registers; mDebugger->PopulateRegisters(®isters); int stackSize = 0; - for (int stackIdx = 0 ; stackIdx < maxStackTrace; stackIdx++) - { + for (int stackIdx = 0; stackIdx < maxStackTrace; stackIdx++) + { auto pc = registers.GetPC(); if (pc <= 0xFFFF) { @@ -353,7 +369,7 @@ void DbgProfiler::ThreadProc() ProfileAddrEntry* insertedProfileEntry = AddToSet(mProfileAddrEntrySet, stackTrace, stackSize); if (insertedProfileEntry->mEntryIdx == -1) - { + { insertedProfileEntry->mEntryIdx = (int)mProfileAddrEntrySet.size(); // Starts at '1' mPendingProfileEntries.Add(*insertedProfileEntry); } @@ -365,7 +381,7 @@ void DbgProfiler::ThreadProc() entryIdx = -entryIdx; profileThreadInfo->mProfileAddrEntries.push_back(entryIdx); } - + ::ResumeThread(thread->mHThread); int elapsedTime = timeGetTime() - startTick; @@ -379,7 +395,7 @@ void DbgProfiler::ThreadProc() } } - mIsRunning = false; + mIsRunning = false; mEndTick = BFTickCount(); } @@ -394,7 +410,7 @@ void DbgProfiler::Start() BF_ASSERT(!mIsRunning); mNeedsProcessing = true; - mIsRunning = true; + mIsRunning = true; auto thread = BfpThread_Create(ThreadProcThunk, (void*)this, 128 * 1024, BfpThreadCreateFlag_StackSizeReserve); BfpThread_Release(thread); } @@ -439,22 +455,25 @@ String DbgProfiler::GetThreadList() for (auto threadId : mThreadIdList) { auto threadInfo = mThreadInfo[threadId]; - result += StrFormat("%d\t%s\n", threadId, threadInfo->mName.c_str()); + int cpuUsage = 0; + if (threadInfo->mTotalSamples > 0) + cpuUsage = 100 - (threadInfo->mTotalIdleSamples * 100 / threadInfo->mTotalSamples); + result += StrFormat("%d\t%d\t%s\n", threadId, cpuUsage, threadInfo->mName.c_str()); } return result; } void DbgProfiler::AddEntries(String& str, Array& procEntries, int rangeStart, int rangeEnd, int stackIdx, ProfileProcId* findProc) -{ +{ struct _QueuedEntry { int mRangeIdx; int mRangeEnd; - int mStackIdx; + int mStackIdx; }; Array<_QueuedEntry> workQueue; - + auto _AddEntries = [&](int rangeStart, int rangeEnd, int stackIdx, ProfileProcId* findProc) { int selfSampleCount = 0; @@ -521,7 +540,7 @@ void DbgProfiler::AddEntries(String& str, Array& procEntries, _QueuedEntry entry; entry.mRangeIdx = rangeStart; entry.mRangeEnd = rangeEnd; - entry.mStackIdx = stackIdx; + entry.mStackIdx = stackIdx; workQueue.Add(entry); }; _AddEntries(rangeStart, rangeEnd, stackIdx, findProc); @@ -529,7 +548,7 @@ void DbgProfiler::AddEntries(String& str, Array& procEntries, while (!workQueue.IsEmpty()) { auto& entry = workQueue.back(); - + bool addedChild = false; while (entry.mRangeIdx < entry.mRangeEnd) { @@ -539,7 +558,7 @@ void DbgProfiler::AddEntries(String& str, Array& procEntries, entry.mRangeIdx++; continue; } - + int nextStackIdx = entry.mStackIdx + 1; auto nextFindProc = procEntry->mData[procEntry->mSize - 1 - nextStackIdx]; _AddEntries(entry.mRangeIdx, entry.mRangeEnd, nextStackIdx, nextFindProc); @@ -552,7 +571,7 @@ void DbgProfiler::AddEntries(String& str, Array& procEntries, if (entry.mStackIdx != -1) str += "-\n"; workQueue.pop_back(); - } + } } } @@ -608,7 +627,10 @@ void DbgProfiler::HandlePendingEntries() symbolName += StrFormat("0x%@", addr); } - procId = Get(symbolName); + bool isNew = false; + procId = Get(symbolName, &isNew); + if (isNew) + procId->mIsIdle = mIdleSymbolNames.Contains(symbolName); } if (reverse) @@ -640,11 +662,11 @@ void DbgProfiler::Process() AutoCrit autoCrit(mDebugger->mDebugManager->mCritSect); mNeedsProcessing = false; - + int time = mTotalActiveSamplingMS; BF_ASSERT(mProfileAddrEntries.IsEmpty()); - + mProfileAddrEntries.Resize(mProfileAddrEntrySet.size() + 1); for (auto& val : mProfileAddrEntrySet) mProfileAddrEntries[val.mEntryIdx] = &val; @@ -654,16 +676,35 @@ void DbgProfiler::Process() for (auto& val : mProfileProcEntrySet) mProfileProcEntries[val.mEntryIdx] = &val; + for (auto threadKV : mThreadInfo) + { + auto threadInfo = threadKV.mValue; + + for (auto addrEntryIdx : threadInfo->mProfileAddrEntries) + { + if (addrEntryIdx < 0) + { + addrEntryIdx = -addrEntryIdx; + } + + int procEntryIdx = mProfileAddrToProcMap[addrEntryIdx]; + auto procEntry = mProfileProcEntries[procEntryIdx]; + + auto curProc = procEntry->mData[0]; + if (curProc->mIsIdle) + threadInfo->mTotalIdleSamples++; + } + } } String DbgProfiler::GetCallTree(int threadId, bool reverse) -{ +{ if (mNeedsProcessing) Process(); AutoCrit autoCrit(mDebugger->mDebugManager->mCritSect); - BF_ASSERT(!mIsRunning); + BF_ASSERT(!mIsRunning); Array procEntries; @@ -714,10 +755,10 @@ String DbgProfiler::GetCallTree(int threadId, bool reverse) int idleTicks = totalSampleCount - totalActiveSampleCount; if (idleTicks != 0) str += StrFormat("\t%d\t0\n-\n", idleTicks); - + AddEntries(str, procEntries, 0, (int)procEntries.size(), -1, NULL); - - str += "-\n"; + + str += "-\n"; //BF_ASSERT(childSampleCount == totalSampleCount); diff --git a/IDEHelper/Profiler.h b/IDEHelper/Profiler.h index b8a0a64a..018fa548 100644 --- a/IDEHelper/Profiler.h +++ b/IDEHelper/Profiler.h @@ -67,6 +67,7 @@ class ProfileProcId { public: String mProcName; + bool mIsIdle; }; class ProfileProdIdEntry @@ -104,12 +105,14 @@ class ProfileThreadInfo public: Array mProfileAddrEntries; int mTotalSamples; + int mTotalIdleSamples; String mName; public: ProfileThreadInfo() { mTotalSamples = 0; + mTotalIdleSamples = 0; } }; @@ -143,6 +146,7 @@ public: Dictionary mProcMap; // Keyed on either DwSubprogram or DwSymbol. Multiple pointers can reference the same ProfileProcId (in the case of inlined functions, for example) HashSet mUniqueProcSet; + HashSet mIdleSymbolNames; public: void ThreadProc(); @@ -171,7 +175,7 @@ public: void HandlePendingEntries(); void Process(); void DoClear(); - ProfileProcId* Get(const StringImpl& str); + ProfileProcId* Get(const StringImpl& str, bool* outIsNew = NULL); public: DbgProfiler(WinDebugger* debugger); From 15a2cdfeedb2577354986b8401796ece3a6f4643 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 28 Dec 2021 08:45:28 -0500 Subject: [PATCH 134/139] Make test methods from extensions work (including static blocks) --- IDEHelper/Compiler/BfCompiler.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/IDEHelper/Compiler/BfCompiler.cpp b/IDEHelper/Compiler/BfCompiler.cpp index 9e2138b0..20c184c5 100644 --- a/IDEHelper/Compiler/BfCompiler.cpp +++ b/IDEHelper/Compiler/BfCompiler.cpp @@ -827,7 +827,7 @@ void BfCompiler::GetTestMethods(BfVDataModule* bfModule, Array& test auto _CheckMethod = [&](BfTypeInstance* typeInstance, BfMethodInstance* methodInstance) { - auto project = typeInstance->mTypeDef->mProject; + auto project = methodInstance->mMethodDef->mDeclaringType->mProject; if (project->mTargetType != BfTargetType_BeefTest) return; if (project != bfModule->mProject) @@ -897,6 +897,16 @@ void BfCompiler::GetTestMethods(BfVDataModule* bfModule, Array& test if (typeInstance == NULL) continue; + if (typeInstance->mTypeDef->IsGlobalsContainer()) + { + NOP; + } + + if (typeInstance->mTypeDef->mProject->mName == "BeefTest") + { + NOP; + } + if (typeInstance->IsUnspecializedType()) continue; @@ -915,7 +925,8 @@ void BfCompiler::EmitTestMethod(BfVDataModule* bfModule, Array& test auto methodInstance = testMethod.mMethodInstance; auto typeInstance = methodInstance->GetOwner(); testMethod.mName += bfModule->TypeToString(typeInstance); - testMethod.mName += "."; + if (!testMethod.mName.IsEmpty()) + testMethod.mName += "."; testMethod.mName += methodInstance->mMethodDef->mName; testMethod.mName += "\t"; From 3570d2a87b261bf2e81a72d895fa8ab160022397 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 28 Dec 2021 09:26:11 -0500 Subject: [PATCH 135/139] Fixed Dispose case --- BeefTools/BeefPerf/src/BPApp.bf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BeefTools/BeefPerf/src/BPApp.bf b/BeefTools/BeefPerf/src/BPApp.bf index 730ec048..fffe1822 100644 --- a/BeefTools/BeefPerf/src/BPApp.bf +++ b/BeefTools/BeefPerf/src/BPApp.bf @@ -505,7 +505,7 @@ namespace BeefPerf subMenu = root.AddMenuItem("&Debug"); subMenu.AddMenuItem("GC Collect", null, new (menu) => { - if (Profiler.StartSampling() case .Ok(let id)) + if (Profiler.StartSampling() case .Ok(var id)) { GC.Collect(); id.Dispose(); From 252fe13a5d26273eeb35cd4ed6394c486f9cc635 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 28 Dec 2021 09:44:25 -0500 Subject: [PATCH 136/139] Allow <=> on bools --- BeefLibs/corlib/src/Boolean.bf | 5 +++++ IDEHelper/Compiler/BfExprEvaluator.cpp | 13 +++++++++---- IDEHelper/Compiler/BfResolvedTypeUtils.h | 2 ++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/BeefLibs/corlib/src/Boolean.bf b/BeefLibs/corlib/src/Boolean.bf index 57b6be83..deaf0e09 100644 --- a/BeefLibs/corlib/src/Boolean.bf +++ b/BeefLibs/corlib/src/Boolean.bf @@ -17,6 +17,11 @@ namespace System strBuffer.Append(((bool)this) ? TrueString : FalseString); } + public static int operator<=>(Boolean a, Boolean b) + { + return (SelfBase)a <=> (SelfBase)b; + } + public int GetHashCode() { return ((bool)this) ? 1 : 0; diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index b5e621b4..bb2dd1f5 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -22477,6 +22477,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfType* resultType, BfIRValue convL auto primType = (BfPrimitiveType*)resultType; if (primType->mTypeDef->mTypeCode == BfTypeCode_Boolean) { + bool passThrough = false; switch (binaryOp) { case BfBinaryOp_Equality: @@ -22503,16 +22504,20 @@ void BfExprEvaluator::PerformBinaryOperation(BfType* resultType, BfIRValue convL mResult = BfTypedValue(mModule->mBfIRBuilder->CreateXor(convLeftValue, convRightValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); break; + case BfBinaryOp_Compare: + passThrough = true; + break; default: if (mModule->PreFail()) mModule->Fail("Invalid operation for booleans", opToken); break; } - return; + if (!passThrough) + return; } } - if ((!resultType->IsIntegral()) && (!resultType->IsFloat())) + if ((!resultType->IsIntegralOrBool()) && (!resultType->IsFloat())) { if (mModule->PreFail()) mModule->Fail(StrFormat("Cannot perform operation on type '%s'", mModule->TypeToString(resultType).c_str()), opToken); @@ -22617,7 +22622,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfType* resultType, BfIRValue convL mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpGTE(convLeftValue, convRightValue, resultType->IsSigned()), mModule->GetPrimitiveType(BfTypeCode_Boolean)); break; - case BfBinaryOp_Compare: + case BfBinaryOp_Compare: { auto intType = mModule->GetPrimitiveType(BfTypeCode_IntPtr); if ((convLeftValue.IsConst()) && (convRightValue.IsConst())) @@ -22638,7 +22643,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfType* resultType, BfIRValue convL mResult = BfTypedValue(mModule->GetConstValue(0, mModule->GetPrimitiveType(BfTypeCode_IntPtr)), intType); } } - else if ((resultType->IsIntegral()) && (resultType->mSize < intType->mSize)) + else if ((resultType->IsIntegralOrBool()) && (resultType->mSize < intType->mSize)) { auto leftIntValue = mModule->mBfIRBuilder->CreateNumericCast(convLeftValue, resultType->IsSigned(), BfTypeCode_IntPtr); auto rightIntValue = mModule->mBfIRBuilder->CreateNumericCast(convRightValue, resultType->IsSigned(), BfTypeCode_IntPtr); diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index cd59cf14..ee281ccf 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -571,6 +571,7 @@ public: virtual bool IsBoolean() { return false; } virtual bool IsInteger() { return false; } virtual bool IsIntegral() { return false; } + virtual bool IsIntegralOrBool() { return false; } virtual bool IsIntPtr() { return false; } virtual bool IsSigned() { return false; } virtual bool IsSignedInt() { return false; } @@ -627,6 +628,7 @@ public: virtual bool IsValueTypeOrValueTypePtr() override { return true; } virtual bool IsBoolean() override { return mTypeDef->mTypeCode == BfTypeCode_Boolean; } virtual bool IsIntegral() override { return (mTypeDef->mTypeCode >= BfTypeCode_Int8) && (mTypeDef->mTypeCode <= BfTypeCode_Char32); } + virtual bool IsIntegralOrBool() override { return (mTypeDef->mTypeCode >= BfTypeCode_Boolean) && (mTypeDef->mTypeCode <= BfTypeCode_Char32); } virtual bool IsInteger() override { return (mTypeDef->mTypeCode >= BfTypeCode_Int8) && (mTypeDef->mTypeCode <= BfTypeCode_UIntUnknown); } virtual bool IsIntPtr() override { return (mTypeDef->mTypeCode == BfTypeCode_IntPtr) || (mTypeDef->mTypeCode == BfTypeCode_UIntPtr); } virtual bool IsIntPtrable() override From 0204e666da73d3b73a3bbe97013dff3c84ef1c49 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 28 Dec 2021 09:44:41 -0500 Subject: [PATCH 137/139] Another idol symbol added --- IDEHelper/Profiler.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/IDEHelper/Profiler.cpp b/IDEHelper/Profiler.cpp index ba6e6c8b..8749cd2b 100644 --- a/IDEHelper/Profiler.cpp +++ b/IDEHelper/Profiler.cpp @@ -107,6 +107,7 @@ DbgProfiler::DbgProfiler(WinDebugger* debugger) : mShutdownEvent(true) mIdleSymbolNames.Add("NtWaitForAlertByThreadId"); mIdleSymbolNames.Add("NtWaitForSingleObject"); mIdleSymbolNames.Add("NtWaitForMultipleObjects"); + mIdleSymbolNames.Add("ZwRemoveIoCompletion"); } DbgProfiler::~DbgProfiler() From deae8fe1e3fd7ba68191108e7c5a31a2931f0961 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 28 Dec 2021 10:09:39 -0500 Subject: [PATCH 138/139] Fixed default args with test methods --- IDEHelper/Compiler/BfCompiler.cpp | 38 +++++++++++++++---------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/IDEHelper/Compiler/BfCompiler.cpp b/IDEHelper/Compiler/BfCompiler.cpp index 20c184c5..7953d190 100644 --- a/IDEHelper/Compiler/BfCompiler.cpp +++ b/IDEHelper/Compiler/BfCompiler.cpp @@ -897,16 +897,6 @@ void BfCompiler::GetTestMethods(BfVDataModule* bfModule, Array& test if (typeInstance == NULL) continue; - if (typeInstance->mTypeDef->IsGlobalsContainer()) - { - NOP; - } - - if (typeInstance->mTypeDef->mProject->mName == "BeefTest") - { - NOP; - } - if (typeInstance->IsUnspecializedType()) continue; @@ -1034,8 +1024,11 @@ void BfCompiler::EmitTestMethod(BfVDataModule* bfModule, Array& test else { for (int defaultIdx = 0; defaultIdx < (int)methodInstance->mDefaultValues.size(); defaultIdx++) - { - auto castedVal = bfModule->Cast(methodInstance->mMethodDef->GetRefNode(), methodInstance->mDefaultValues[defaultIdx], methodInstance->GetParamType(defaultIdx)); + { + auto constHolder = methodInstance->GetOwner()->mConstHolder; + auto defaultTypedValue = methodInstance->mDefaultValues[defaultIdx]; + auto defaultVal = bfModule->ConstantToCurrent(constHolder->GetConstant(defaultTypedValue.mValue), constHolder, defaultTypedValue.mType); + auto castedVal = bfModule->Cast(methodInstance->mMethodDef->GetRefNode(), BfTypedValue(defaultVal, defaultTypedValue.mType), methodInstance->GetParamType(defaultIdx)); if (castedVal) { BfExprEvaluator exprEvaluator(bfModule); @@ -7035,27 +7028,34 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory) if (hasTests) { + HashSet projectSet; + for (auto type : mContext->mResolvedTypes) { auto typeInstance = type->ToTypeInstance(); - if ((typeInstance != NULL) && - (typeInstance->mTypeDef->mProject->mTargetType == BfTargetType_BeefTest)) - { - bool typeHasTest = false; + if (typeInstance != NULL) + { for (auto& methodInstanceGroup : typeInstance->mMethodInstanceGroups) { if (methodInstanceGroup.mDefault != NULL) { auto methodInstance = methodInstanceGroup.mDefault; + auto project = methodInstance->mMethodDef->mDeclaringType->mProject; + if (project->mTargetType != BfTargetType_BeefTest) + continue; if ((methodInstance->GetCustomAttributes() != NULL) && (methodInstance->GetCustomAttributes()->Contains(mTestAttributeTypeDef))) { - typeHasTest = true; + projectSet.Add(project); } } } - if (typeHasTest) - mContext->MarkUsedModules(typeInstance->mTypeDef->mProject, typeInstance->mModule); + if (!projectSet.IsEmpty()) + { + for (auto project : projectSet) + mContext->MarkUsedModules(project, typeInstance->mModule); + projectSet.Clear(); + } } } } From 4f1ed19bb800efcbff12c2cef4f8f0dfe9c44d75 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 28 Dec 2021 10:10:03 -0500 Subject: [PATCH 139/139] More fixes to test methods in extensions --- IDEHelper/Compiler/BfModuleTypeUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 21ac3a07..b8f17a4f 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -5650,7 +5650,7 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance) } } - if (typeInstance->mTypeDef->mProject->mTargetType == BfTargetType_BeefTest) + if (methodInstance->mMethodDef->mDeclaringType->mProject->mTargetType == BfTargetType_BeefTest) { if ((customAttributes != NULL) && (customAttributes->Contains(mCompiler->mTestAttributeTypeDef))) {