Ver código fonte

Added System.Compiler compile-time values

Brian Fiete 5 anos atrás
pai
commit
25f44ae133

+ 29 - 0
BeefLibs/corlib/src/Compiler.bf

@@ -0,0 +1,29 @@
+namespace System
+{
+	static class Compiler
+	{
+		[LinkName("#CallerLineNum")]
+		public static extern int CallerLineNum;
+
+		[LinkName("#CallerFilePath")]
+		public static extern String CallerFilePath;
+
+		[LinkName("#CallerFileName")]
+		public static extern String CallerFileName;
+
+		[LinkName("#CallerFileDir")]
+		public static extern String CallerFileDir;
+
+		[LinkName("#CallerMemberName")]
+		public static extern String CallerMemberName;
+
+		[LinkName("#CallerProject")]
+		public static extern String CallerProject;
+
+		[LinkName("#CallerExpression")]
+		public static extern String[Int32.MaxValue] CallerExpression;
+
+		[LinkName("#TimeLocal")]
+		public static extern String TimeLocal;
+	}
+}

+ 8 - 13
BeefLibs/corlib/src/Diagnostics/Debug.bf

@@ -5,27 +5,22 @@ namespace System.Diagnostics
 #if !DEBUG
 		[SkipCall]
 #endif
-        public static void Assert(bool condition) 
-        {
-			if (!condition)
-				Internal.FatalError("Assert failed", 1);
-        }
-
-#if !DEBUG
-		[SkipCall]
-#endif
-		public static void Assert(bool condition, String error) 
+		public static void Assert(bool condition, String error = Compiler.CallerExpression[0], String filePath = Compiler.CallerFilePath, int line = Compiler.CallerLineNum) 
 		{
 			if (!condition)
-				Internal.FatalError(error, 1);
+			{
+				String failStr = scope .()..AppendF("Assert failed: {} at line {} in {}", error, line, filePath);
+				Internal.FatalError(failStr, 1);
+			}
 		}
 
 #if !DEBUG
 		[SkipCall]
 #endif
-		public static void FatalError(String msg = "Fatal error encountered")
+		public static void FatalError(String msg = "Fatal error encountered", String filePath = Compiler.CallerFilePath, int line = Compiler.CallerLineNum)
 		{
-			Internal.FatalError(msg, 1);
+			String failStr = scope .()..AppendF("{} at line {} in {}", msg, line, filePath);
+			Internal.FatalError(failStr, 1);
 		}
 
 #if !DEBUG

+ 11 - 12
BeefLibs/corlib/src/Runtime.bf

@@ -306,27 +306,26 @@ namespace System
 		}
 
 		[NoReturn]
-		public static void FatalError(String msg = "Fatal error encountered")
+		public static void FatalError(String msg = "Fatal error encountered", String filePath = Compiler.CallerFilePath, int line = Compiler.CallerLineNum)
 		{
-			Internal.FatalError(msg, 1);
+			String failStr = scope .()..AppendF("{} at line {} in {}", msg, line, filePath);
+			Internal.FatalError(failStr, 1);
 		}
 
 		[NoReturn]
-		public static void NotImplemented()
+		public static void NotImplemented(String filePath = Compiler.CallerFilePath, int line = Compiler.CallerLineNum)
 		{
-			Internal.FatalError("Not Implemented", 1);
+			String failStr = scope .()..AppendF("Not Implemented at line {} in {}", line, filePath);
+			Internal.FatalError(failStr, 1);
 		}
 
-		public static void Assert(bool condition) 
+		public static void Assert(bool condition, String error = Compiler.CallerExpression[0], String filePath = Compiler.CallerFilePath, int line = Compiler.CallerLineNum) 
 		{
 			if (!condition)
-				Internal.FatalError("Assert failed", 1);
-		}
-
-		public static void Assert(bool condition, String error) 
-		{
-			if (!condition)
-				Internal.FatalError(error, 1);
+			{
+				String failStr = scope .()..AppendF("Assert failed: {} at line {} in {}", error, line, filePath);
+				Internal.FatalError(failStr, 1);
+			}
 		}
 	}
 }

+ 1 - 1
IDEHelper/Compiler/BfCompiler.cpp

@@ -4129,7 +4129,7 @@ void BfCompiler::ProcessAutocompleteTempType()
 
 		if ((fieldDef->mFieldDeclaration != NULL) && (fieldDef->mFieldDeclaration->mAttributes != NULL))
 		{
-			auto customAttrs = module->GetCustomAttributes(fieldDef->mFieldDeclaration->mAttributes, BfAttributeTargets_Field);
+			auto customAttrs = module->GetCustomAttributes(fieldDef->mFieldDeclaration->mAttributes, fieldDef->mIsStatic ? BfAttributeTargets_StaticField : BfAttributeTargets_Field);
 			delete customAttrs;
 		}
 

+ 13 - 13
IDEHelper/Compiler/BfConstResolver.cpp

@@ -89,9 +89,8 @@ BfTypedValue BfConstResolver::Resolve(BfExpression* expr, BfType* wantType, BfCo
 	if (wantType != NULL)
 		mExpectingType = wantType;
 	VisitChildNoRef(expr);
+	
 	mResult = GetResult();
-	if (mResult)
-		mResult = mModule->LoadValue(mResult);
 	if ((mResult) && (wantType != NULL))
 	{
 		auto typeInst = mResult.mType->ToTypeInstance();
@@ -113,17 +112,18 @@ BfTypedValue BfConstResolver::Resolve(BfExpression* expr, BfType* wantType, BfCo
 				}
 				else
 				{
-					int stringId = mModule->GetStringPoolIdx(mResult.mValue);
-					BF_ASSERT(stringId >= 0);
-
-					if ((flags & BfConstResolveFlag_RemapFromStringId) != 0)
+					int stringId = mModule->GetStringPoolIdx(mResult.mValue);					
+					if (stringId != -1)
 					{
-						ignoreWrites.Restore();
-						mModule->mBfIRBuilder->PopulateType(mResult.mType);
-						return BfTypedValue(mModule->GetStringObjectValue(stringId), mResult.mType);
+						if ((flags & BfConstResolveFlag_RemapFromStringId) != 0)
+						{
+							ignoreWrites.Restore();
+							mModule->mBfIRBuilder->PopulateType(mResult.mType);
+							return BfTypedValue(mModule->GetStringObjectValue(stringId), mResult.mType);
+						}
+
+						return BfTypedValue(mModule->mBfIRBuilder->CreateConst(BfTypeCode_StringId, stringId), toType);
 					}
-
-					return BfTypedValue(mModule->mBfIRBuilder->CreateConst(BfTypeCode_StringId, stringId), toType);
 				}
 			}
 		}
@@ -180,10 +180,10 @@ BfTypedValue BfConstResolver::Resolve(BfExpression* expr, BfType* wantType, BfCo
 		if (isConst)
 		{
 			auto constant = mModule->mBfIRBuilder->GetConstant(mResult.mValue);
-			if (constant->mConstType == BfConstType_GlobalVar)
+			if ((constant->mConstType == BfConstType_GlobalVar) && ((mBfEvalExprFlags & BfConstResolveFlag_AllowGlobalVariable) != 0))
 				isConst = false;
 		}
-
+		
 		if ((!isConst) && ((mBfEvalExprFlags & BfEvalExprFlags_AllowNonConst) == 0))
 		{			
 			mModule->Fail("Expression does not evaluate to a constant value", expr);

+ 2 - 1
IDEHelper/Compiler/BfConstResolver.h

@@ -16,7 +16,8 @@ enum BfConstResolveFlags
 	BfConstResolveFlag_NoCast = 2,
 	BfConstResolveFlag_AllowSoftFail = 4,
 	BfConstResolveFlag_RemapFromStringId = 8,
-	BfConstResolveFlag_ArrayInitSize = 0x10
+	BfConstResolveFlag_ArrayInitSize = 0x10,
+	BfConstResolveFlag_AllowGlobalVariable = 0x20,
 };
 
 class BfConstResolver : public BfExprEvaluator

+ 101 - 9
IDEHelper/Compiler/BfExprEvaluator.cpp

@@ -21,6 +21,7 @@
 #include "BfFixits.h"
 
 #pragma warning(pop)
+#pragma warning(disable:4996)
 
 #include "BeefySysLib/util/AllocDebug.h"
 
@@ -5840,6 +5841,88 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
 					argValue = mModule->GetDefaultTypedValue(wantType, false, BfDefaultValueKind_Addr);
 				}
 			}
+			else if (foreignConst->mConstType == BfConstType_GlobalVar)
+			{
+				auto globalVar = (BfGlobalVar*)foreignConst;
+				if (globalVar->mName[0] == '#')
+				{
+					if (strcmp(globalVar->mName, "#CallerLineNum") == 0)
+					{
+						argValue = BfTypedValue(mModule->GetConstValue(mModule->mCurFilePosition.mCurLine + 1), mModule->GetPrimitiveType(BfTypeCode_Int32));
+					}
+					else if (strcmp(globalVar->mName, "#CallerFilePath") == 0)
+					{
+						String filePath = "";
+						if (mModule->mCurFilePosition.mFileInstance != NULL)
+							filePath = mModule->mCurFilePosition.mFileInstance->mParser->mFileName;
+						argValue = BfTypedValue(mModule->GetStringObjectValue(filePath),
+							mModule->ResolveTypeDef(mModule->mCompiler->mStringTypeDef));
+					}
+					else if (strcmp(globalVar->mName, "#CallerFileName") == 0)
+					{
+						String filePath = "";
+						if (mModule->mCurFilePosition.mFileInstance != NULL)
+							filePath = mModule->mCurFilePosition.mFileInstance->mParser->mFileName;
+						argValue = BfTypedValue(mModule->GetStringObjectValue(GetFileName(filePath)),
+							mModule->ResolveTypeDef(mModule->mCompiler->mStringTypeDef));
+					}
+					else if (strcmp(globalVar->mName, "#CallerFileDir") == 0)
+					{
+						String filePath = "";
+						if (mModule->mCurFilePosition.mFileInstance != NULL)
+							filePath = mModule->mCurFilePosition.mFileInstance->mParser->mFileName;
+						argValue = BfTypedValue(mModule->GetStringObjectValue(GetFileDir(filePath)),
+							mModule->ResolveTypeDef(mModule->mCompiler->mStringTypeDef));
+					}
+					else if (strcmp(globalVar->mName, "#CallerMemberName") == 0)
+					{
+						String memberName = "";
+						if (mModule->mCurMethodInstance != NULL)
+							memberName = mModule->MethodToString(mModule->mCurMethodInstance);
+						argValue = BfTypedValue(mModule->GetStringObjectValue(memberName),
+							mModule->ResolveTypeDef(mModule->mCompiler->mStringTypeDef));
+					}
+					else if (strcmp(globalVar->mName, "#CallerProject") == 0)
+					{
+						String projectName = "";
+						if (mModule->mCurMethodInstance != NULL)
+							projectName = mModule->mCurMethodInstance->mMethodDef->mDeclaringType->mProject->mName;
+						argValue = BfTypedValue(mModule->GetStringObjectValue(projectName),
+							mModule->ResolveTypeDef(mModule->mCompiler->mStringTypeDef));
+					}
+					else
+					{
+						argValue = mModule->GetCompilerFieldValue(globalVar->mName);
+					}					
+				}
+			}
+			else if (foreignConst->mConstType == BfConstType_GEP32_2)
+			{
+				auto constGep32_2 = (BfConstantGEP32_2*)foreignConst;
+				auto gepTarget = methodInstance->GetOwner()->mConstHolder->GetConstantById(constGep32_2->mTarget);
+				if (gepTarget->mConstType == BfConstType_GlobalVar)
+				{
+					auto globalVar = (BfGlobalVar*)gepTarget;
+					if (globalVar->mName[0] == '#')
+					{
+						if (strcmp(globalVar->mName, "#CallerExpression") == 0)
+						{
+							int exprIdx = constGep32_2->mIdx1;
+							if ((exprIdx >= 0) && (exprIdx <= (int)argValues.size()))
+							{
+								argValue = BfTypedValue(mModule->GetStringObjectValue(argValues[exprIdx].mExpression->ToString()),
+									mModule->ResolveTypeDef(mModule->mCompiler->mStringTypeDef));
+							}
+							else
+							{
+								mModule->Fail("CallerExpression index out of bounds", targetSrc);
+								argValue = BfTypedValue(mModule->GetStringObjectValue(""),
+									mModule->ResolveTypeDef(mModule->mCompiler->mStringTypeDef));
+							}
+						}
+					}
+				}
+			}
 
 			if (!argValue)
 			{				
@@ -17516,9 +17599,12 @@ void BfExprEvaluator::Visit(BfIndexerExpression* indexerExpr)
 		{			
 			if (target.mType->IsSizeAligned())
 			{
-				auto ptrType = mModule->CreatePointerType(underlyingType);
-				auto ptrValue = mModule->mBfIRBuilder->CreateBitCast(target.mValue, mModule->mBfIRBuilder->MapType(ptrType));
-				auto gepResult = mModule->mBfIRBuilder->CreateInBoundsGEP(ptrValue, indexArgument.mValue);
+// 				auto ptrType = mModule->CreatePointerType(underlyingType);
+// 				auto ptrValue = mModule->mBfIRBuilder->CreateBitCast(target.mValue, mModule->mBfIRBuilder->MapType(ptrType));
+// 				auto gepResult = mModule->mBfIRBuilder->CreateInBoundsGEP(ptrValue, indexArgument.mValue);
+// 				mResult = BfTypedValue(gepResult, underlyingType, target.IsReadOnly() ? BfTypedValueKind_ReadOnlyAddr : BfTypedValueKind_Addr);
+
+				auto gepResult = mModule->mBfIRBuilder->CreateInBoundsGEP(target.mValue, mModule->GetConstValue(0), indexArgument.mValue);
 				mResult = BfTypedValue(gepResult, underlyingType, target.IsReadOnly() ? BfTypedValueKind_ReadOnlyAddr : BfTypedValueKind_Addr);
 			}
 			else
@@ -18942,13 +19028,19 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
 			skipOpOverload = true;
 		else if (BfBinOpEqualityCheck(binaryOp))
 		{
-			auto leftConstant = mModule->mBfIRBuilder->GetConstant(leftValue.mValue);
-			auto rightConstant = mModule->mBfIRBuilder->GetConstant(rightValue.mValue);
+			if (!leftValue.IsAddr())
+			{
+				auto leftConstant = mModule->mBfIRBuilder->GetConstant(leftValue.mValue);
+					if ((leftConstant != NULL) && (leftConstant->IsNull()))
+						skipOpOverload = true;
+			}
 			
-			if ((leftConstant != NULL) && (leftConstant->IsNull()))
-				skipOpOverload = true;
-			if ((rightConstant != NULL) && (rightConstant->IsNull()))
-				skipOpOverload = true;
+			if (!rightValue.IsAddr())
+			{
+				auto rightConstant = mModule->mBfIRBuilder->GetConstant(rightValue.mValue);
+				if ((rightConstant != NULL) && (rightConstant->IsNull()))
+					skipOpOverload = true;
+			}
 		}		
 
 		if (!skipOpOverload)

+ 25 - 10
IDEHelper/Compiler/BfIRBuilder.cpp

@@ -2675,9 +2675,12 @@ void BfIRBuilder::CreateDbgTypeDefinition(BfType* type)
 
 							StringT<128> staticVarName;
 							BfMangler::Mangle(staticVarName, mModule->mCompiler->GetMangleKind(), fieldInstance);
-							String fieldName = DbgGetStaticFieldName(fieldInstance);
-							DbgCreateGlobalVariable(diForwardDecl, fieldName, staticVarName, fileDIScope, 0,
-								constDIType, false, staticValue, memberType);
+							if (!staticVarName.StartsWith("#"))
+							{
+								String fieldName = DbgGetStaticFieldName(fieldInstance);
+								DbgCreateGlobalVariable(diForwardDecl, fieldName, staticVarName, fileDIScope, 0,
+									constDIType, false, staticValue, memberType);
+							}
 						}
 						else if (resolvedFieldType->IsValuelessType())
 						{
@@ -2788,14 +2791,17 @@ void BfIRBuilder::CreateDbgTypeDefinition(BfType* type)
 						resolvedFieldDIType, flags, BfIRValue());
 					diFieldTypes.push_back(memberType);
 
-					auto staticValue = mModule->ReferenceStaticField(fieldInstance);
-					if (staticValue.mValue)
+					StringT<128> staticVarName;
+					BfMangler::Mangle(staticVarName, mModule->mCompiler->GetMangleKind(), fieldInstance);
+					if (!staticVarName.StartsWith('#'))
 					{
-						StringT<128> staticVarName;
-						BfMangler::Mangle(staticVarName, mModule->mCompiler->GetMangleKind(), fieldInstance);
-						String fieldName = DbgGetStaticFieldName(fieldInstance);
-						DbgCreateGlobalVariable(diForwardDecl, fieldName, staticVarName, fileDIScope, 0,
-							resolvedFieldDIType, false, staticValue.mValue, memberType);
+						auto staticValue = mModule->ReferenceStaticField(fieldInstance);
+						if (staticValue.mValue)
+						{
+							String fieldName = DbgGetStaticFieldName(fieldInstance);
+							DbgCreateGlobalVariable(diForwardDecl, fieldName, staticVarName, fileDIScope, 0,
+								resolvedFieldDIType, false, staticValue.mValue, memberType);
+						}
 					}
 				}
 			}
@@ -4101,6 +4107,15 @@ BfIRValue BfIRBuilder::CreateInBoundsGEP(BfIRValue val, BfIRValue idx0)
 
 BfIRValue BfIRBuilder::CreateInBoundsGEP(BfIRValue val, BfIRValue idx0, BfIRValue idx1)
 {
+	if ((val.IsConst()) && (idx0.IsConst()) && (idx1.IsConst()))
+	{
+		auto idx0Constant = GetConstant(idx0);
+		auto idx1Constant = GetConstant(idx1);
+
+		if ((IsInt(idx0Constant->mTypeCode)) && (IsInt(idx1Constant->mTypeCode)))
+			return CreateInBoundsGEP(val, idx0Constant->mInt32, idx1Constant->mInt32);
+	}
+
 	BfIRValue retVal = WriteCmd(BfIRCmd_InBoundsGEP2, val, idx0, idx1);
 	NEW_CMD_INSERTED_IRVALUE;
 	return retVal;

+ 30 - 1
IDEHelper/Compiler/BfMangler.cpp

@@ -2243,7 +2243,36 @@ void BfMangler::Mangle(StringImpl& outStr, MangleKind mangleKind, BfMethodInstan
 }
 
 void BfMangler::Mangle(StringImpl& outStr, MangleKind mangleKind, BfFieldInstance* fieldInstance)
-{
+{	
+	if (fieldInstance->mCustomAttributes != NULL)
+	{
+		auto module = fieldInstance->mOwner->mModule;
+		auto linkNameAttr = fieldInstance->mCustomAttributes->Get(module->mCompiler->mLinkNameAttributeTypeDef);
+		if (linkNameAttr != NULL)
+		{
+			if (linkNameAttr->mCtorArgs.size() == 1)
+			{
+				if (module->TryGetConstString(fieldInstance->mOwner->mConstHolder, linkNameAttr->mCtorArgs[0], outStr))
+					if (!outStr.IsWhitespace())
+						return;
+
+				auto constant = fieldInstance->mOwner->mConstHolder->GetConstant(linkNameAttr->mCtorArgs[0]);
+				if (constant != NULL)
+				{
+					if (constant->mInt32 == 1) // C
+					{
+						outStr += fieldInstance->GetFieldDef()->mName;
+						return;
+					}
+					else if (constant->mInt32 == 2) // CPP
+					{
+						//mangleContext.mCPPMangle = true;
+					}
+				}
+			}
+		}
+	}
+
 	if (mangleKind == BfMangler::MangleKind_GNU)
 		outStr += BfGNUMangler::MangleStaticFieldName(fieldInstance->mOwner, fieldInstance->GetFieldDef()->mName);
 	else

+ 73 - 15
IDEHelper/Compiler/BfModule.cpp

@@ -2,8 +2,8 @@
 
 #include "BeefySysLib/util/AllocDebug.h"
 
-#pragma warning(push) // 6
 #pragma warning(disable:4996)
+#pragma warning(push) // 6
 
 #include "BfCompiler.h"
 #include "BfSystem.h"
@@ -1097,7 +1097,7 @@ void BfModule::EnsureIRBuilder(bool dbgVerifyCodeGen)
 			//  code as we walk the AST
 			//mBfIRBuilder->mDbgVerifyCodeGen = true;			
 			if (
-                (mModuleName == "-")
+                (mModuleName == "BeefTest_TestProgram")
 				//|| (mModuleName == "BeefTest2_ClearColorValue")
 				//|| (mModuleName == "Tests_FuncRefs")
 				)
@@ -3381,6 +3381,7 @@ BfCheckedKind BfModule::GetDefaultCheckedKind()
 
 void BfModule::AddFailType(BfTypeInstance* typeInstance)
 {
+	BF_ASSERT(typeInstance != NULL);
 	mContext->mFailTypes.Add(typeInstance);
 }
 
@@ -3454,7 +3455,7 @@ void BfModule::CreateStaticField(BfFieldInstance* fieldInstance, bool isThreadLo
 		BfLogSysM("Creating static field Module:%p Type:%p\n", this, fieldType);
 		StringT<128> staticVarName;
 		BfMangler::Mangle(staticVarName, mCompiler->GetMangleKind(), fieldInstance);
-		if (!fieldType->IsValuelessType())
+		if ((!fieldType->IsValuelessType()) && (!staticVarName.StartsWith("#")))
 		{
 			BfIRValue globalVar = mBfIRBuilder->CreateGlobalVariable(					
 				mBfIRBuilder->MapType(fieldType, BfIRPopulateType_Eventually_Full),
@@ -3538,11 +3539,13 @@ void BfModule::ResolveConstField(BfTypeInstance* typeInstance, BfFieldInstance*
 	{	
 		if (!fieldDef->mTypeRef->IsA<BfPointerTypeRef>())
 		{
+			SetAndRestoreValue<BfTypeInstance*> prevTypeInstance(mCurTypeInstance, typeInstance);
 			Fail("Extern consts must be pointer types", fieldDef->mFieldDeclaration->mTypeRef);
 		}
 
 		if (fieldDef->mInitializer != NULL)
 		{
+			SetAndRestoreValue<BfTypeInstance*> prevTypeInstance(mCurTypeInstance, typeInstance);
 			Fail("Extern consts cannot have initializers", fieldDef->mFieldDeclaration->mNameNode);
 		}
 	}
@@ -9995,7 +9998,7 @@ void BfModule::ClearConstData()
 }
 
 BfTypedValue BfModule::GetTypedValueFromConstant(BfConstant* constant, BfIRConstHolder* constHolder, BfType* wantType)
-{				
+{		
 	switch (constant->mTypeCode)
 	{
 	case BfTypeCode_StringId:
@@ -10057,12 +10060,20 @@ BfTypedValue BfModule::GetTypedValueFromConstant(BfConstant* constant, BfIRConst
 		}
 		break;
 	default: break;
-	}
-	
+	}		
 	BfIRValue irValue = ConstantToCurrent(constant, constHolder, wantType);
 	BF_ASSERT(irValue);
 	if (!irValue)
 		return BfTypedValue();
+
+	if (constant->mConstType == BfConstType_GlobalVar)
+	{
+		auto result = BfTypedValue(irValue, wantType, true);
+		if (!wantType->IsComposite())
+			result = LoadValue(result);
+		return result;
+	}
+
 	return BfTypedValue(irValue, wantType, false);
 }
 
@@ -10839,6 +10850,25 @@ BfTypedValue BfModule::LoadValue(BfTypedValue typedValue, BfAstNode* refNode, bo
 	if ((typedValue.mType->IsValuelessType()) || (typedValue.mType->IsVar()))
 		return BfTypedValue(mBfIRBuilder->GetFakeVal(), typedValue.mType, false);
 
+	if (typedValue.mValue.IsConst())
+	{
+		auto constantValue = mBfIRBuilder->GetConstant(typedValue.mValue);
+		if (constantValue != NULL)
+		{
+			if (constantValue->mConstType == BfConstType_GlobalVar)
+			{
+				auto globalVar = (BfGlobalVar*)constantValue;
+				if (globalVar->mName[0] == '#')
+				{
+					BfTypedValue result = GetCompilerFieldValue(globalVar->mName);
+					if (result)
+						return result;
+					return GetDefaultTypedValue(typedValue.mType);
+				}
+			}
+		}
+	}
+
 	BfIRValue loadedVal = typedValue.mValue;
 	if (loadedVal)
 	{
@@ -12603,14 +12633,28 @@ void BfModule::HadSlotCountDependency()
 	mUsedSlotCount = BF_MAX(mCompiler->mMaxInterfaceSlots, 0);	
 }
 
+BfTypedValue BfModule::GetCompilerFieldValue(const StringImpl& str)
+{
+	if (str == "#TimeLocal")
+	{
+		time_t rawtime;
+		time(&rawtime);
+		tm* timeinfo = localtime(&rawtime);
+		char result[32];
+		sprintf(result, "%d/%.2d/%.2d %.2d:%.2d:%.2d",
+			1900 + timeinfo->tm_year,
+			timeinfo->tm_mon,
+			timeinfo->tm_mday,
+			timeinfo->tm_hour,
+			timeinfo->tm_min,
+			timeinfo->tm_sec);
+		return BfTypedValue(GetStringObjectValue(result), ResolveTypeDef(mCompiler->mStringTypeDef));
+	}
+	return BfTypedValue();
+}
+
 BfTypedValue BfModule::ReferenceStaticField(BfFieldInstance* fieldInstance)
 {		
-	if (mIsScratchModule)
-	{
-		// Just fake it for the extern and unspecialized modules		
-		return BfTypedValue(mBfIRBuilder->GetFakeVal(), fieldInstance->GetResolvedType(), true);
-	}
-	
 	BfIRValue globalValue;
 	
 	auto fieldDef = fieldInstance->GetFieldDef();
@@ -12626,7 +12670,13 @@ BfTypedValue BfModule::ReferenceStaticField(BfFieldInstance* fieldInstance)
 		{
 			return GetDefaultTypedValue(fieldInstance->GetResolvedType());
 		}
-	}		
+	}	
+
+	if (mIsScratchModule)
+	{
+		// Just fake it for the extern and unspecialized modules		
+		return BfTypedValue(mBfIRBuilder->CreateConstNull(), fieldInstance->GetResolvedType(), true);
+	}
 	
 	BfIRValue* globalValuePtr = NULL;
 	if (mStaticFieldRefs.TryGetValue(fieldInstance, &globalValuePtr))
@@ -12648,8 +12698,12 @@ BfTypedValue BfModule::ReferenceStaticField(BfFieldInstance* fieldInstance)
 		PopulateType(typeType);
 		if ((typeType != NULL) && (!typeType->IsValuelessType()))
 		{
+			BfIRType irType = mBfIRBuilder->MapType(typeType);
+
+			SetAndRestoreValue<bool> prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, mBfIRBuilder->mIgnoreWrites || staticVarName.StartsWith('#'));
+
 			globalValue = mBfIRBuilder->CreateGlobalVariable(
-				mBfIRBuilder->MapType(typeType),
+				irType,
 				false,
 				BfIRLinkageType_External,
 				BfIRValue(),
@@ -16601,6 +16655,10 @@ void BfModule::EmitGCMarkMembers()
 
 							if ((fieldDef->mIsStatic) && (!fieldDef->mIsConst))
 							{
+								StringT<128> staticVarName;
+								BfMangler::Mangle(staticVarName, mCompiler->GetMangleKind(), &fieldInst);
+								if (staticVarName.StartsWith('#'))
+									continue;
 								markVal = ReferenceStaticField(&fieldInst);
 							}
 							else if (!fieldDef->mIsStatic)
@@ -20368,7 +20426,7 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
 			else
 			{
 				BfConstResolver constResolver(this);
-				defaultValue = constResolver.Resolve(paramDef->mParamDeclaration->mInitializer, resolvedParamType, BfConstResolveFlag_NoCast);
+				defaultValue = constResolver.Resolve(paramDef->mParamDeclaration->mInitializer, resolvedParamType, (BfConstResolveFlags)(BfConstResolveFlag_NoCast | BfConstResolveFlag_AllowGlobalVariable));
 				if ((defaultValue) && (defaultValue.mType != resolvedParamType))
 				{
 					SetAndRestoreValue<bool> prevIgnoreWrite(mBfIRBuilder->mIgnoreWrites, true);

+ 1 - 0
IDEHelper/Compiler/BfModule.h

@@ -1548,6 +1548,7 @@ public:
 	bool CheckModifyValue(BfTypedValue& typedValue, BfAstNode* refNode, const char* modifyType = NULL);
 	BfIRValue GetInterfaceSlotNum(BfTypeInstance* ifaceType);
 	void HadSlotCountDependency();
+	BfTypedValue GetCompilerFieldValue(const StringImpl& str);
 	BfTypedValue ReferenceStaticField(BfFieldInstance* fieldInstance);
 	BfTypedValue GetThis();
 	BfLocalVariable* GetThisVariable();