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

Merge branch 'master' of https://github.com/beefytech/Beef into FuzzyAutoComplete

This commit is contained in:
Simon Lübeß 2021-12-17 18:05:39 +01:00
parent c2c7431620
commit b70745ef1e
48 changed files with 2975 additions and 918 deletions

View file

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

View file

@ -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

View file

@ -1,8 +1,189 @@
using System.Reflection;
using System.Diagnostics;
using System.Collections;
using System.Security.Cryptography;
namespace System
{
static class Compiler
{
public abstract class Generator
{
public enum Flags
{
None = 0,
AllowRegenerate = 1
}
public String mCmdInfo = new String() ~ delete _;
public Dictionary<StringView, StringView> mParams = new .() ~ delete _;
public abstract String Name { get; }
public StringView ProjectName => mParams["ProjectName"];
public StringView ProjectDir => mParams["ProjectDir"];
public StringView FolderDir => mParams["FolderDir"];
public StringView Namespace => mParams["Namespace"];
public StringView DefaultNamespace => mParams["DefaultNamespace"];
public StringView WorkspaceName => mParams["WorkspaceName"];
public StringView WorkspaceDir => mParams["WorkspaceDir"];
public StringView DateTime => mParams["DateTime"];
public bool IsRegenerating => mParams.GetValueOrDefault("Regenerating") == "True";
public void Fail(StringView error)
{
mCmdInfo.AppendF("error\t");
error.QuoteString(mCmdInfo);
mCmdInfo.Append("\n");
}
public void AddEdit(StringView dataName, StringView label, StringView defaultValue)
{
mCmdInfo.AppendF($"addEdit\t");
dataName.QuoteString(mCmdInfo);
mCmdInfo.Append("\t");
label.QuoteString(mCmdInfo);
mCmdInfo.Append("\t");
defaultValue.QuoteString(mCmdInfo);
mCmdInfo.Append("\n");
}
public void AddCombo(StringView dataName, StringView label, StringView defaultValue, Span<StringView> values)
{
mCmdInfo.AppendF($"addCombo\t");
dataName.QuoteString(mCmdInfo);
mCmdInfo.Append("\t");
label.QuoteString(mCmdInfo);
mCmdInfo.Append("\t");
defaultValue.QuoteString(mCmdInfo);
for (var value in values)
{
mCmdInfo.Append("\t");
value.QuoteString(mCmdInfo);
}
mCmdInfo.Append("\n");
}
public void AddCheckbox(StringView dataName, StringView label, bool defaultValue)
{
mCmdInfo.AppendF($"addCheckbox\t");
dataName.QuoteString(mCmdInfo);
mCmdInfo.Append("\t");
label.QuoteString(mCmdInfo);
mCmdInfo.AppendF($"\t{defaultValue}\n");
}
public bool GetString(StringView key, String outVal)
{
if (mParams.TryGetAlt(key, var matchKey, var value))
{
outVal.Append(value);
return true;
}
return false;
}
public virtual void InitUI()
{
}
public virtual void Generate(String outFileName, String outText, ref Flags generateFlags)
{
}
static String GetName<T>() where T : Generator
{
T val = scope T();
String str = val.Name;
return str;
}
void HandleArgs(String args)
{
for (var line in args.Split('\n', .RemoveEmptyEntries))
{
int tabPos = line.IndexOf('\t');
var key = line.Substring(0, tabPos);
var value = line.Substring(tabPos + 1);
if (mParams.TryAdd(key, var keyPtr, var valuePtr))
{
*keyPtr = key;
*valuePtr = value;
}
}
}
static String InitUI<T>(String args) where T : Generator
{
T val = scope T();
val.HandleArgs(args);
val.InitUI();
return val.mCmdInfo;
}
static String Generate<T>(String args) where T : Generator
{
T val = scope T();
val.HandleArgs(args);
String fileName = scope .();
String outText = scope .();
Flags flags = .None;
val.Generate(fileName, outText, ref flags);
val.mCmdInfo.Append("fileName\t");
fileName.QuoteString(val.mCmdInfo);
val.mCmdInfo.Append("\n");
val.mCmdInfo.Append("data\n");
if (flags.HasFlag(.AllowRegenerate))
{
bool writeArg = false;
for (var line in args.Split('\n', .RemoveEmptyEntries))
{
int tabPos = line.IndexOf('\t');
var key = line.Substring(0, tabPos);
var value = line.Substring(tabPos + 1);
if (key == "Generator")
writeArg = true;
if (writeArg)
{
val.mCmdInfo.AppendF($"// {key}={value}\n");
}
}
var hash = MD5.Hash(.((.)outText.Ptr, outText.Length));
val.mCmdInfo.AppendF($"// GenHash={hash}\n\n");
}
val.mCmdInfo.Append(outText);
return val.mCmdInfo;
}
}
public class NewClassGenerator : Generator
{
public override String Name => "New Class";
public override void InitUI()
{
AddEdit("name", "Class Name", "");
}
public override void Generate(String outFileName, String outText, ref Flags generateFlags)
{
var name = mParams["name"];
if (name.EndsWith(".bf", .OrdinalIgnoreCase))
name.RemoveFromEnd(3);
outFileName.Append(name);
outText.AppendF(
$"""
namespace {Namespace}
{{
class {name}
{{
}}
}}
""");
}
}
public struct MethodBuilder
{
void* mNative;
@ -43,7 +224,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;
@ -76,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);
@ -94,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)
{

View file

@ -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<int64, double>(0x8000000000000000UL);
public const double NegativeZero = -0.0;
public static int operator<=>(Double a, Double b)
{

View file

@ -163,7 +163,7 @@ namespace System
public static mixin Mark<T>(T val) where T : struct
{
#if BF_ENABLE_REALTIME_LEAK_CHECK
val.[Friend]GCMarkMembers();
val.[Friend, Unbound]GCMarkMembers();
#endif
}

View file

@ -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<void> 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;
}
@ -176,7 +172,12 @@ namespace System.IO
public override Result<void> Close()
{
return Flush();
let ret = Flush();
mPos = 0;
mBufferPos = -Int32.MinValue;
mBufferEnd = -Int32.MinValue;
return ret;
}
}
}

View file

@ -0,0 +1,580 @@
// 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<int, CommonDialog> sHookMap = new Dictionary<int, CommonDialog>() ~
{
Debug.Assert(sHookMap.Count == 0);
delete _;
};
public static Monitor sMonitor = new Monitor() ~ delete _;
public Result<DialogResult> 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<DialogResult> RunDialog(Windows.HWnd hWndOwner);
}
abstract class FileDialog : CommonDialog
{
protected abstract Result<DialogResult> RunFileDialog(ref Windows.OpenFileName ofn);
protected override Result<DialogResult> 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<void> 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<void> 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<DialogResult> 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
protected abstract Result<Windows.COM_IFileDialog*> CreateVistaDialog();
private Result<DialogResult> TryRunDialogVista(Windows.HWnd hWndOwner)
{
Windows.COM_IFileDialog* dialog;
if (!(CreateVistaDialog() case .Ok(out dialog)))
return .Err;
OnBeforeVistaDialog(dialog);
dialog.VT.Show(dialog, hWndOwner);
List<String> 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<String> files);
private Result<void> SetFileTypes(Windows.COM_IFileDialog* dialog)
{
List<Windows.COMDLG_FILTERSPEC> 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

View file

@ -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,16 +425,37 @@ namespace System.IO
mFileAccess = access;
}
public override Result<void> 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<void> 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()

View file

@ -57,7 +57,7 @@ namespace System.IO
ShowNewFolderButton = true;
}
protected Result<DialogResult> RunDialog_New(Windows.HWnd hWndOwner, FolderBrowserDialog.COM_IFileDialog* fileDialog)
protected Result<DialogResult> 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<DialogResult> 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

View file

@ -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<int, CommonDialog> sHookMap = new Dictionary<int, CommonDialog>() ~
{
Debug.Assert(sHookMap.Count == 0);
delete _;
};
public static Monitor sMonitor = new Monitor() ~ delete _;
public Result<DialogResult> 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<DialogResult> RunDialog(Windows.HWnd hWndOwner);
}
abstract class FileDialog : CommonDialog
{
protected abstract Result<DialogResult> RunFileDialog(ref Windows.OpenFileName ofn);
protected override Result<DialogResult> 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<void> 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<void> 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<DialogResult> 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,73 @@ namespace System.IO
return DialogResult.OK;
}
protected override void ProcessVistaFiles(Windows.COM_IFileDialog* dialog, List<String> 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)
{
Windows.COM_IShellItemArray* results = null;
openDialog.VT.GetResults(openDialog, out results);
if (results != null)
{
results.VT.GetCount(results, let count);
for (uint32 i < count)
{
Windows.COM_IShellItem* item = null;
results.VT.GetItemAt(results, i, out item);
if (item != null)
{
let filePath = GetFilePathFromShellItem!(item);
if (filePath != null)
files.Add(filePath);
}
}
results.VT.Release(results);
}
}
else
{
Windows.COM_IShellItem* shellItem = null;
openDialog.VT.GetResult(openDialog, out shellItem);
if (shellItem != null)
{
let filePath = GetFilePathFromShellItem!(shellItem);
if (filePath != null)
files.Add(filePath);
shellItem.VT.Release(shellItem);
}
}
}
protected override Result<Windows.COM_IFileDialog*> 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;
}
}
}

View file

@ -94,6 +94,48 @@ namespace System.IO
return DialogResult.OK;
}
protected override void ProcessVistaFiles(Windows.COM_IFileDialog* dialog, System.Collections.List<String> 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;
Windows.COM_IShellItem* shellItem = null;
saveDialog.VT.GetResult(saveDialog, out shellItem);
if (shellItem != null)
{
let filePath = GetFilePathFromShellItem!(shellItem);
if (filePath != null)
files.Add(filePath);
shellItem.VT.Release(shellItem);
}
}
protected override Result<Windows.COM_IFileDialog*> 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;
}
}
}

View file

@ -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);

View file

@ -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;
}
}

View file

@ -52,7 +52,7 @@ namespace IDETest
void MethodB()
{
function void() f = => MethodA<T2>; //FAIL Method 'IDETest.Generics.ClassA<T1, T2>.MethodA<T2>(int a)' does not match function 'function void()'
function void() f = => MethodA<T2>; //FAIL Method 'void IDETest.Generics.ClassA<T1, T2>.MethodA<T2>(int a)' does not match function 'function void()'
}
}

View file

@ -2,6 +2,11 @@ namespace System
{
class Compiler
{
public class Generator
{
}
public static class Options
{
[LinkName("#AllocStackCount")]

View file

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

View file

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

View file

@ -37,6 +37,7 @@ namespace IDE
public ProjectFolder mParentFolder;
public String mName = new String() ~ delete _;
public String mComment = new String() ~ delete _;
public bool mDetached;
public virtual bool IncludeInMap
{
@ -105,6 +106,7 @@ namespace IDE
public virtual void Detach()
{
mDetached = true;
ReleaseRef();
}
}
@ -353,7 +355,7 @@ namespace IDE
return .SimpleSource;
}
public override void Dispose()
public void ClearEditData()
{
if (mEditData != null)
{
@ -363,6 +365,11 @@ namespace IDE
}
}
public override void Dispose()
{
ClearEditData();
}
public override void Detach()
{
Dispose();
@ -843,6 +850,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);
}
}

View file

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

View file

@ -0,0 +1,882 @@
using Beefy.theme.dark;
using Beefy.widgets;
using System;
using System.Collections;
using Beefy.gfx;
using Beefy.events;
using IDE.Compiler;
using System.Threading;
using System.Security.Cryptography;
using Beefy.theme;
namespace IDE.ui
{
class GenerateListView : DarkListView
{
public GenerateDialog mNewClassDialog;
}
class GenerateKindBar : DarkComboBox
{
public class Entry
{
public String mTypeName ~ delete _;
public String mName ~ delete _;
}
public static Dictionary<String, int32> sMRU = new Dictionary<String, int32>() ~ delete _;
public static int32 sCurrentMRUIndex = 1;
public GenerateDialog mNewClassDialog;
public List<Entry> mEntries = new List<Entry>() ~ DeleteContainerAndItems!(_);
public List<Entry> mShownEntries = new List<Entry>() ~ delete _;
public String mFilterString ~ delete _;
public String mCurLocation = new String() ~ delete _;
public bool mIgnoreChange = false;
public this(GenerateDialog dialog)
{
mNewClassDialog = dialog;
mLabelAlign = FontAlign.Left;
Label = "";
mLabelX = GS!(16);
mPopulateMenuAction.Add(new => PopulateNavigationBar);
MakeEditable();
mEditWidget.mOnContentChanged.Add(new => NavigationBarChanged);
mEditWidget.mOnGotFocus.Add(new (widget) => mEditWidget.mEditWidgetContent.SelectAll());
mEditWidget.mEditWidgetContent.mWantsUndo = false;
mEditWidget.mOnSubmit.Add(new => mNewClassDialog.[Friend]EditSubmitHandler);
mFocusDropdown = false;
}
public ~this()
{
}
static ~this()
{
for (var key in sMRU.Keys)
delete key;
}
public void SetLocation(String location)
{
if (mCurMenuWidget == null)
{
mIgnoreChange = true;
mEditWidget.SetText(location);
mEditWidget.mEditWidgetContent.SelectAll();
// SetText can attempt to scroll to the right to make the cursor position visible. Just scroll back to the start.
mEditWidget.HorzScrollTo(0);
//mNewClassDialog.SelectKind();
mIgnoreChange = false;
}
}
private void PopulateNavigationBar(Menu menu)
{
List<StringView> findStrs = null;
if (mFilterString != null)
findStrs = scope:: List<StringView>(mFilterString.Split(' '));
EntryLoop: for (int32 entryIdx = 0; entryIdx < mEntries.Count; entryIdx++)
{
var entry = mEntries[entryIdx];
if (findStrs != null)
{
for (let findStr in findStrs)
{
if (entry.mName.IndexOf(findStr, true) == -1)
continue EntryLoop;
}
}
mShownEntries.Add(entry);
var menuItem = menu.AddItem(entry.mName);
menuItem.mOnMenuItemSelected.Add(new (evt) =>
{
mNewClassDialog.mPendingUIFocus = true;
ShowEntry(entryIdx, entry);
});
}
}
void ShowEntry(int32 entryIdx, Entry entry)
{
mEditWidget.SetText(entry.mName);
mEditWidget.mEditWidgetContent.SelectAll();
mCurMenuWidget?.Close();
}
private void NavigationBarChanged(EditEvent theEvent)
{
if (mIgnoreChange)
return;
var editWidget = (EditWidget)theEvent.mSender;
var searchText = scope String();
editWidget.GetText(searchText);
searchText.Trim();
mFilterString = searchText;
ShowDropdown();
mFilterString = null;
}
bool mIgnoreShowDropdown;
public override MenuWidget ShowDropdown()
{
if (mIgnoreShowDropdown)
return null;
mIgnoreShowDropdown = true;
defer { mIgnoreShowDropdown = false; }
if (!mEditWidget.mHasFocus)
SetFocus();
if (mFilterString == null)
mEditWidget.Content.SelectAll();
mShownEntries.Clear();
base.ShowDropdown();
int32 bestItem = -1;
int32 bestPri = -1;
var menuWidget = (DarkMenuWidget)mCurMenuWidget;
for (int32 itemIdx = 0; itemIdx < menuWidget.mItemWidgets.Count; itemIdx++)
{
var menuItemWidget = (DarkMenuItem)menuWidget.mItemWidgets[itemIdx];
int32 pri;
sMRU.TryGetValue(menuItemWidget.mMenuItem.mLabel, out pri);
if (pri > bestPri)
{
bestItem = itemIdx;
bestPri = pri;
}
}
if (bestItem != -1)
{
mCurMenuWidget.mOnSelectionChanged.Add(new => SelectionChanged);
mCurMenuWidget.SetSelection(bestItem);
}
return menuWidget;
}
void SelectionChanged(int selIdx)
{
if (mEditWidget.mEditWidgetContent.HasSelection())
{
bool prevIgnoreShowDropdown = mIgnoreShowDropdown;
mIgnoreShowDropdown = true;
mEditWidget.SetText("");
mIgnoreShowDropdown = prevIgnoreShowDropdown;
}
}
public override void MenuClosed()
{
}
}
class GenerateDialog : IDEDialog
{
public class UIEntry
{
public String mName ~ delete _;
public String mData ~ delete _;
public String mLabel ~ delete _;
public Widget mWidget;
}
public enum ThreadState
{
None,
Executing,
Done
}
public bool mPendingGenList;
public GenerateKindBar mKindBar;
public ThreadState mThreadState;
public int mThreadWaitCount;
public String mNamespace ~ delete _;
public String mProjectName ~ delete _;
public ProjectItem mProjectItem ~ _.ReleaseRef();
public String mFolderPath ~ delete _;
public List<UIEntry> mUIEntries = new .() ~ DeleteContainerAndItems!(_);
public GenerateKindBar.Entry mSelectedEntry;
public GenerateKindBar.Entry mPendingSelectedEntry;
public String mUIData ~ delete _;
public float mUIHeight = 0;
public OutputPanel mOutputPanel;
public bool mPendingUIFocus;
public bool mSubmitting;
public bool mSubmitQueued;
public bool mRegenerating;
public this(ProjectItem projectItem, bool allowHashMismatch = false)
{
var project = projectItem.mProject;
mProjectItem = projectItem;
mProjectItem.AddRef();
mNamespace = new .();
var projectFolder = projectItem as ProjectFolder;
var projectSource = projectItem as ProjectSource;
if (projectSource != null)
{
projectFolder = projectSource.mParentFolder;
mRegenerating = true;
}
projectFolder.GetRelDir(mNamespace); mNamespace.Replace('/', '.'); mNamespace.Replace('\\', '.'); mNamespace.Replace(" ", "");
if (mNamespace.StartsWith("src."))
{
mNamespace.Remove(0, 4);
if (!project.mBeefGlobalOptions.mDefaultNamespace.IsWhiteSpace)
{
mNamespace.Insert(0, ".");
mNamespace.Insert(0, project.mBeefGlobalOptions.mDefaultNamespace);
}
}
else if (projectItem.mParentFolder == null)
{
mNamespace.Clear();
mNamespace.Append(project.mBeefGlobalOptions.mDefaultNamespace);
}
else
mNamespace.Clear();
mFolderPath = projectFolder.GetFullImportPath(.. new .());
mProjectName = new String(projectItem.mProject.mProjectName);
mWindowFlags = .ClientSized | .TopMost | .Caption | .Border | .SysMenu | .Resizable | .PopupPosition;
if (!mRegenerating)
{
AddOkCancelButtons(new (evt) =>
{
Submit();
evt.mCloseDialog = false;
}, null, 0, 1);
}
Title = "Generate File";
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 includes 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())
{
if (mRegenerating)
args.Append("Regenerating\tTrue\n");
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));
RehupMinSize();
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 ShowError(StringView error)
{
if (mOutputPanel == null)
{
IDEApp.Beep(.Error);
mOutputPanel = new OutputPanel();
AddWidget(mOutputPanel);
ResizeComponents();
}
String str = scope .();
str.Append(error);
str.Replace('\r', '\n');
str.Append("\n");
mOutputPanel.WriteSmart(str);
}
public override void Update()
{
base.Update();
if ((!mKindBar.mEditWidget.mHasFocus) && (mWidgetWindow.mHasFocus))
{
var sel = mPendingSelectedEntry ?? mSelectedEntry;
String editText = mKindBar.mEditWidget.GetText(.. scope .());
if ((sel != null) && (editText != sel.mName))
{
mKindBar.mIgnoreChange = true;
mKindBar.mEditWidget.SetText(sel.mName);
mKindBar.mIgnoreChange = false;
}
}
if (mThreadState == .Done)
{
if (mSelectedEntry != null)
{
List<UIEntry> oldEntries = scope .();
Dictionary<String, UIEntry> entryMap = scope .();
if (!mSubmitting)
{
for (var uiEntry in mUIEntries)
{
if (!entryMap.TryAdd(uiEntry.mName, uiEntry))
oldEntries.Add(uiEntry);
}
mUIEntries.Clear();
}
if (mUIData != null)
{
if (mOutputPanel != null)
{
mOutputPanel.RemoveSelf();
DeleteAndNullify!(mOutputPanel);
}
String fileName = default;
StringView genText = default;
bool hadError = false;
if (mUIData.IsEmpty)
{
gApp.Fail("Generator failed to return results");
}
LinesLoop: for (var line in mUIData.Split('\n', .RemoveEmptyEntries))
{
var partItr = line.Split('\t');
var kind = partItr.GetNext().Value;
switch (kind)
{
case "!error":
ShowError(line.Substring(7));
case "addEdit":
if (mSubmitting)
break;
UIEntry uiEntry = new UIEntry();
uiEntry.mName = partItr.GetNext().Value.UnQuoteString(.. new .());
uiEntry.mLabel = partItr.GetNext().Value.UnQuoteString(.. new .());
var defaultValue = partItr.GetNext().Value.UnQuoteString(.. scope .());
DarkEditWidget editWidget = new DarkEditWidget();
uiEntry.mWidget = editWidget;
editWidget.SetText(defaultValue);
editWidget.mEditWidgetContent.SelectAll();
editWidget.mOnSubmit.Add(new => EditSubmitHandler);
AddWidget(editWidget);
mUIEntries.Add(uiEntry);
mTabWidgets.Add(editWidget);
case "addCombo":
if (mSubmitting)
break;
UIEntry uiEntry = new UIEntry();
uiEntry.mName = partItr.GetNext().Value.UnQuoteString(.. new .());
uiEntry.mLabel = partItr.GetNext().Value.UnQuoteString(.. new .());
var defaultValue = partItr.GetNext().Value.UnQuoteString(.. scope .());
List<String> choices = new List<String>();
DarkComboBox comboBox = new DarkComboBox();
while (partItr.GetNext() case .Ok(let val))
{
choices.Add(val.UnQuoteString(.. new .()));
}
comboBox.mOnDeleted.Add(new (widget) => { DeleteContainerAndItems!(choices); });
comboBox.mPopulateMenuAction.Add(new (menu) =>
{
for (var choice in choices)
{
var item = menu.AddItem(choice);
item.mOnMenuItemSelected.Add(new (menu) =>
{
comboBox.Label = menu.mLabel;
});
}
});
uiEntry.mWidget = comboBox;
comboBox.Label = defaultValue;
AddWidget(comboBox);
mUIEntries.Add(uiEntry);
mTabWidgets.Add(comboBox);
case "addCheckbox":
if (mSubmitting)
break;
UIEntry uiEntry = new UIEntry();
uiEntry.mName = partItr.GetNext().Value.UnQuoteString(.. new .());
uiEntry.mLabel = partItr.GetNext().Value.UnQuoteString(.. new .());
var defaultValue = partItr.GetNext().Value;
DarkCheckBox checkbox = new DarkCheckBox();
uiEntry.mWidget = checkbox;
checkbox.Label = uiEntry.mLabel;
checkbox.Checked = defaultValue == "True";
AddWidget(checkbox);
mUIEntries.Add(uiEntry);
mTabWidgets.Add(checkbox);
case "error":
hadError = true;
gApp.Fail(line.Substring(6).UnQuoteString(.. scope .()));
case "fileName":
fileName = line.Substring(9).UnQuoteString(.. scope:: .());
case "options":
case "data":
genText = .(mUIData, @line.MatchPos + 1);
break LinesLoop;
}
}
ResizeComponents();
RehupMinSize();
if (fileName?.EndsWith(".bf", .OrdinalIgnoreCase) == true)
fileName.RemoveFromEnd(3);
if ((fileName != null) && (!mRegenerating))
{
for (char8 c in fileName.RawChars)
{
if (!c.IsLetterOrDigit && c != '_')
{
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 ((hadError) && (mRegenerating) && (mOutputPanel == null))
{
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 ..." : "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 - ((mDefaultButton != null) ? GS!(40) : GS!(0)));
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 - ((mDefaultButton != null) ? GS!(44) : GS!(12)), GS!(32)));
mUIHeight = Math.Max(mUIHeight, GS!(160));
}
}
public override void Close()
{
if (mThreadState == .Executing)
{
var bfCompiler = gApp.mBfResolveCompiler;
bfCompiler.RequestFastFinish(true);
bfCompiler.WaitForBackground();
}
base.Close();
}
public override void Submit()
{
mDefaultButton.mDisabled = true;
mEscButton.mDisabled = true;
if (mSubmitQueued)
return;
mSubmitQueued = true;
mPendingSelectedEntry = mPendingSelectedEntry ?? mSelectedEntry;
}
}
}

View file

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

View file

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

View file

@ -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);

View file

@ -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;

View file

@ -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();
@ -1023,7 +1019,7 @@ void BeCOFFObject::DbgStartSection(int sectionNum)
void BeCOFFObject::DbgEndSection()
{
auto& outS = mDebugSSect.mData;
int totalLen = outS.GetPos() - mSectionStartPos;
int totalLen = outS.GetPos() - mSectionStartPos;
*((int32*)&outS.mData[mSectionStartPos - 4]) = totalLen;
mSectionStartPos = -1;
while ((outS.GetPos() & 3) != 0)
@ -1132,7 +1128,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 +2142,7 @@ bool BeCOFFObject::Generate(BeModule* module, const StringImpl& fileName)
if (mWriteToLib)
{
DynMemStream memStream;
Generate(module);
mStream = &memStream;

View file

@ -1647,7 +1647,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"

View file

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

View file

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

View file

@ -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)

View file

@ -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;
@ -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;
@ -6373,16 +6375,23 @@ void BfExprEvaluator::FinishDeferredEvals(BfResolvedArgs& argValues)
auto variableDeclaration = BfNodeDynCast<BfVariableDeclaration>((*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);
}
}
}
}
@ -10139,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<BfAssignmentExpression>(elementExpr))
@ -11133,8 +11148,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++;
@ -11696,7 +11710,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)
{
@ -11704,8 +11722,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_ResolveGenericParamNames | BfMethodNameFlag_IncludeReturnType | BfMethodNameFlag_IncludeMut)).c_str(), bindTypeName,
mModule->TypeToString(delegateTypeInstance).c_str()), delegateBindExpr->mTarget);
}
mResult = BfTypedValue();
@ -11725,7 +11743,7 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr)
}
bool hasIncompatibleCallingConventions = !mModule->mSystem->IsCompatibleCallingConvention(methodInstance->mCallingConvention, bindMethodInstance->mCallingConvention);
auto _GetInvokeMethodName = [&]()
{
String methodName = "Invoke$";
@ -11789,7 +11807,7 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr)
if (mExpectingType->IsFunction())
{
BfIRValue result;
if ((hasIncompatibleCallingConventions) && (mModule->HasCompiledOutput()))
if ((hasIncompatibleCallingConventions) && (mModule->HasExecutedOutput()))
{
//
{
@ -11799,11 +11817,14 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr)
if (result)
{
String methodName = _GetInvokeMethodName();
String methodName = _GetInvokeMethodName();
SizedArray<BfIRType, 8> 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();
@ -11949,7 +11970,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 +12051,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 +12229,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 +12247,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 +13209,7 @@ BfLambdaInstance* BfExprEvaluator::GetLambdaInstance(BfLambdaBindExpression* lam
mModule->mIncompleteMethodCount++;
SetAndRestoreValue<BfClosureState*> prevClosureState(mModule->mCurMethodState->mClosureState, &closureState);
if (mModule->HasCompiledOutput())
if (mModule->HasExecutedOutput())
mModule->SetupIRMethod(methodInstance, methodInstance->mIRFunction, methodInstance->mAlwaysInline);
// This keeps us from giving errors twice. ProcessMethod can give errors when we capture by value but needed to
@ -14415,7 +14436,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 +19738,7 @@ void BfExprEvaluator::Visit(BfIndexerExpression* indexerExpr)
}
}
}
else if (((mModule->HasCompiledOutput()) || (mModule->mIsComptimeModule)) &&
else if (((mModule->HasExecutedOutput()) || (mModule->mIsComptimeModule)) &&
(wantsChecks))
{
if (checkedKind == BfCheckedKind_NotSet)

View file

@ -857,6 +857,27 @@ BfIRValue BfIRConstHolder::CreateConstArrayZero(int count)
return irValue;
}
BfIRValue BfIRConstHolder::CreateConstBitCast(BfIRValue val, BfIRType type)
{
auto constVal = GetConstant(val);
auto bitCast = mTempAlloc.Alloc<BfConstantBitCast>();
if ((constVal == NULL) || (constVal->IsNull()))
bitCast->mConstType = BfConstType_BitCastNull;
else
bitCast->mConstType = BfConstType_BitCast;
BF_ASSERT(val.mId != -1);
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<BfTypeOf_Const>();
@ -2970,10 +2991,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 +3112,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
{
@ -4417,25 +4435,7 @@ BfIRValue BfIRBuilder::CreateNot(BfIRValue val)
BfIRValue BfIRBuilder::CreateBitCast(BfIRValue val, BfIRType type)
{
if (val.IsConst())
{
auto constVal = GetConstant(val);
auto bitCast = mTempAlloc.Alloc<BfConstantBitCast>();
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;

View file

@ -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);

View file

@ -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(),
@ -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)
{
@ -10519,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);
@ -10764,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;
}
@ -10860,8 +10873,17 @@ 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);
}
else
newVal = mCurTypeInstance->GetOrCreateConstHolder()->CreateConstNull();
irVal = mCurTypeInstance->GetOrCreateConstHolder()->CreateConstBitCast(newVal, bitcast->mToType);
return;
}
irVal = mCurTypeInstance->CreateConst(constant, mBfIRBuilder);
@ -10986,7 +11008,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);
}
@ -11034,8 +11056,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))
@ -14456,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);
}
@ -15273,14 +15308,18 @@ void BfModule::AssertErrorState()
{
if (mCurTypeInstance->mTypeFailed)
return;
if (mCurTypeInstance->mTypeDef->mSource->mParsingFailed)
if ((mCurTypeInstance->mTypeDef->GetDefinition()->mSource != NULL) && (mCurTypeInstance->mTypeDef->GetDefinition()->mSource->mParsingFailed))
return;
}
if (mCurMethodInstance != NULL)
{
if ((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->mParsingFailed))
if ((mCurMethodState != NULL) && (mCurMethodState->mMixinState != NULL) &&
(mCurMethodState->mMixinState->mMixinMethodInstance->mMethodDef->mDeclaringType->mSource != NULL) &&
(mCurMethodState->mMixinState->mMixinMethodInstance->mMethodDef->mDeclaringType->mSource->mParsingFailed))
return;
}
@ -16203,6 +16242,8 @@ void BfModule::EmitDtorBody()
BfIRValue BfModule::CreateDllImportGlobalVar(BfMethodInstance* methodInstance, bool define)
{
BF_ASSERT(methodInstance->mIsReified);
auto typeInstance = methodInstance->GetOwner();
bool foundDllImportAttr = false;
@ -16467,7 +16508,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()))
@ -17041,7 +17082,7 @@ void BfModule::EmitCtorBody(bool& skipBody)
break;
}
if ((HasCompiledOutput()) && (matchedMethod != NULL))
if ((HasExecutedOutput()) && (matchedMethod != NULL))
{
SizedArray<BfIRValue, 1> args;
auto ctorBodyMethodInstance = GetMethodInstance(mCurTypeInstance->mBaseType, matchedMethod, BfTypeVector());
@ -18486,7 +18527,7 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
return;
}
if (HasCompiledOutput())
if (HasExecutedOutput())
{
BF_ASSERT(mIsModuleMutable);
}
@ -19713,7 +19754,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();
@ -19743,12 +19784,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<BfIRValue, 8> innerParams;
@ -19977,7 +20014,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 +20027,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 +20069,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);
@ -22782,18 +22819,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

View file

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

View file

@ -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;
@ -2198,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();
@ -2210,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);
@ -2747,7 +2750,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++)
{
@ -2927,6 +2930,9 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
{
bool hadType = false;
BfAstNode* deferredErrorNode = NULL;
char* deferredError = NULL;
for (auto baseTypeRef : typeDef->mBaseTypes)
{
SetAndRestoreValue<BfTypeReference*> prevTypeRef(mContext->mCurTypeState->mCurBaseTypeRef, baseTypeRef);
@ -2946,12 +2952,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 +2969,9 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
}
}
if (deferredError != NULL)
Fail(deferredError, deferredErrorNode, true);
if (underlyingType == NULL)
{
underlyingType = GetPrimitiveType(BfTypeCode_Int64);
@ -3305,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;
@ -3694,6 +3726,25 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
if (innerType->IsIncomplete())
PopulateType(innerType, BfPopulateType_Data);
auto innerTypeInst = innerType->ToTypeInstance();
if (innerTypeInst != NULL)
{
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;
dataPos = baseType->mInstSize;
int alignSize = BF_MAX(innerType->mAlign, baseType->mInstAlign);
@ -3997,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);
@ -4054,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);
@ -5658,16 +5715,7 @@ 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 (!matchedMethod->mIsForeignMethodDef)
{
BfMethodInstanceGroup* boxedMethodInstanceGroup = &typeInstance->mMethodInstanceGroups[matchedMethod->mMethodDef->mIdx];
@ -5676,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);
@ -11505,29 +11553,37 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
{
SetAndRestoreValue<bool> 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;
}
}
@ -11755,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));
}

View file

@ -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;
}

View file

@ -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();

View file

@ -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<BfEnumEntryDeclaration>(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<BfBlock>())
{
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<BfTypeDeclaration*> prevTypeDecl(mCurTypeDecl, typeDeclaration);

View file

@ -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;

View file

@ -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;

View file

@ -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()))
@ -1563,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;
}
}
@ -2636,6 +2628,12 @@ void BfTupleType::Finish()
//////////////////////////////////////////////////////////////////////////
BfBoxedType::~BfBoxedType()
{
if ((mTypeDef != NULL) && (mTypeDef->mEmitParent != NULL))
mTypeDef = NULL;
}
BfType* BfBoxedType::GetModifiedElementType()
{
if ((mBoxedFlags & BoxedFlags_StructPtr) != 0)

View file

@ -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
@ -1827,6 +1828,7 @@ class BfCeTypeInfo
public:
Dictionary<int, BfCeTypeEmitEntry> mOnCompileMap;
Dictionary<int, BfCeTypeEmitEntry> mTypeIFaceMap;
Array<int> mPendingInterfaces;
Val128 mHash;
bool mFailed;
BfCeTypeInfo* mNext;
@ -2109,6 +2111,7 @@ public:
mBoxedBaseType = NULL;
mBoxedFlags = BoxedFlags_None;
}
~BfBoxedType();
virtual bool IsBoxed() override { return true; }

View file

@ -793,11 +793,6 @@ BfTypeDef::~BfTypeDef()
{
BfLogSysM("BfTypeDef::~BfTypeDef %p\n", this);
if ((mHash == -1330357811) && (IsEmitted()))
{
NOP;
}
delete mNextRevision;
FreeMembers();
@ -2282,6 +2277,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);
@ -3693,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())
{
@ -3729,6 +3763,7 @@ void BfSystem::RemoveOldData()
void BfSystem::VerifyTypeDef(BfTypeDef* typeDef)
{
#if defined _DEBUG && false
auto _FindTypeDef = [&](BfTypeReference* typeRef)
{
if (auto directStrTypeRef = BfNodeDynCast<BfDirectStrTypeReference>(typeRef))
@ -3762,6 +3797,7 @@ void BfSystem::VerifyTypeDef(BfTypeDef* typeDef)
_FindTypeDef(paramDef->mTypeRef);
}
}
#endif
}
BfTypeOptions* BfSystem::GetTypeOptions(int optionsIdx)

View file

@ -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);

View file

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

View file

@ -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<int32> mInterfaces;
String mEmitData;
String mExitEmitData;
bool mFailed;
@ -697,6 +699,11 @@ public:
mMethodInstance = NULL;
mFailed = false;
}
bool HasEmissions()
{
return !mEmitData.IsEmpty() || !mInterfaces.IsEmpty();
}
};
class CeContext

View file

@ -174,7 +174,61 @@ namespace Tests
public float mY;
public float mZ;
}
class SerializationContext
{
public String mStr = new String() ~ delete _;
public void Serialize<T>(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");
Compiler.EmitAddInterface(type, typeof(ISerializable));
}
}
[Serializable]
struct Foo : this(float x, float y)
{
}
public class ComponentHandler<T>
where T : struct
{
uint8* data;
protected override void GCMarkMembers()
{
T* ptr = (T*)data;
GC.Mark!((*ptr));
}
}
[Test]
public static void TestBasics()
{
@ -209,6 +263,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");
}
}
}

View file

@ -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;
}
}