Sfoglia il codice sorgente

Const string interpolation

Brian Fiete 3 anni fa
parent
commit
8ebd7516d8

+ 9 - 3
BeefLibs/corlib/src/String.bf

@@ -1165,7 +1165,7 @@ namespace System
 		* @param provider The format provider
 		* @returns This method can fail if the format string is invalid.
 		*/
-		public Result<void> AppendF(IFormatProvider provider, StringView format, params Object[] args)
+		public Result<void> AppendF(IFormatProvider provider, StringView format, params Span<Object> args)
 		{
 			if (format.Ptr == null)
 			{
@@ -1240,7 +1240,7 @@ namespace System
 					}
 			        while (ch >= '0' && ch <= '9' && index < 1000000);
 				}
-				if (index >= args.Count) return FormatError();
+				if (index >= args.Length) return FormatError();
 				while (pos < len && (ch = format[pos]) == ' ') pos++;
 				bool leftJustify = false;
 				int width = 0;
@@ -1340,7 +1340,7 @@ namespace System
 			return .Ok;
 		}
 
-		public Result<void> AppendF(StringView format, params Object[] args)
+		public Result<void> AppendF(StringView format, params Span<Object> args)
 		{
 			return AppendF((IFormatProvider)null, format, params args);
 		}
@@ -2475,6 +2475,12 @@ namespace System
 			}
 		}
 
+		[Comptime(ConstEval=true)]
+		public static String ConstF(String format, params Span<Object> args)
+		{
+			return new String()..AppendF(format, params args);
+		}
+
 		public static bool Equals(char8* str1, char8* str2)
 		{
 			for (int i = 0; true; i++)

+ 3 - 3
IDEHelper/Compiler/BfCompiler.cpp

@@ -377,6 +377,7 @@ BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly)
 		
 	mBfObjectTypeDef = NULL;
 	mChar32TypeDef = NULL;
+	mFloatTypeDef = NULL;
 	mDoubleTypeDef = NULL;
 	mMathTypeDef = NULL;
 	mArray1TypeDef = NULL;
@@ -6772,12 +6773,11 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
 	_GetRequiredType("System.UInt8");
 	_GetRequiredType("System.UInt16");
 	_GetRequiredType("System.UInt32");
-	_GetRequiredType("System.UInt64");
-	_GetRequiredType("System.Float");
-	_GetRequiredType("System.Double");
+	_GetRequiredType("System.UInt64");	
 	_GetRequiredType("System.Char8");
 	_GetRequiredType("System.Char16");
 	mChar32TypeDef = _GetRequiredType("System.Char32");
+	mFloatTypeDef = _GetRequiredType("System.Float");
 	mDoubleTypeDef = _GetRequiredType("System.Double");
 	mMathTypeDef = _GetRequiredType("System.Math");
 

+ 1 - 0
IDEHelper/Compiler/BfCompiler.h

@@ -347,6 +347,7 @@ public:
 			
 	BfTypeDef* mBfObjectTypeDef;
 	BfTypeDef* mChar32TypeDef;
+	BfTypeDef* mFloatTypeDef;
 	BfTypeDef* mDoubleTypeDef;
 	BfTypeDef* mMathTypeDef;
 

+ 33 - 7
IDEHelper/Compiler/BfExprEvaluator.cpp

@@ -3785,11 +3785,6 @@ void BfExprEvaluator::Visit(BfLiteralExpression* literalExpr)
 
 void BfExprEvaluator::Visit(BfStringInterpolationExpression* stringInterpolationExpression)
 {
-	if (IsConstEval())
-	{
-		mModule->Fail("Const evaluation of string interpolation not allowed", stringInterpolationExpression);
-	}
-
 	if ((mBfEvalExprFlags & BfEvalExprFlags_StringInterpolateFormat) != 0)
 	{
 		BfVariant variant;
@@ -3799,6 +3794,37 @@ void BfExprEvaluator::Visit(BfStringInterpolationExpression* stringInterpolation
 		return;
 	}
 
+	//
+	{
+		SetAndRestoreValue<BfEvalExprFlags> prevEvalExprFlag(mBfEvalExprFlags);
+		if ((mModule->mAttributeState != NULL) && (mModule->mAttributeState->mCustomAttributes != NULL) && (mModule->mAttributeState->mCustomAttributes->Contains(mModule->mCompiler->mConstEvalAttributeTypeDef)))
+		{
+			mModule->mAttributeState->mUsed = true;
+			mBfEvalExprFlags = (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_Comptime);			
+		}
+
+		if (IsConstEval())
+		{
+			auto stringType = mModule->ResolveTypeDef(mModule->mCompiler->mStringTypeDef);
+			if (stringType != NULL)
+			{
+				SizedArray<BfExpression*, 2> argExprs;
+				argExprs.Add(stringInterpolationExpression);
+				BfSizedArray<BfExpression*> sizedArgExprs(argExprs);
+				BfResolvedArgs argValues(&sizedArgExprs);
+				ResolveArgValues(argValues, BfResolveArgsFlag_InsideStringInterpolationAlloc);
+				auto result = MatchMethod(stringInterpolationExpression, NULL, BfTypedValue(stringType), false, false, "ConstF", argValues, BfMethodGenericArguments());
+				if (result.mType == stringType)
+				{
+					mResult = result;
+					return;
+				}
+			}
+
+			mModule->Fail("Const evaluation of string interpolation not allowed", stringInterpolationExpression);
+		}
+	}	
+
 	if (stringInterpolationExpression->mAllocNode != NULL)
 	{
 		auto stringType = mModule->ResolveTypeDef(mModule->mCompiler->mStringTypeDef)->ToTypeInstance();
@@ -7945,10 +7971,10 @@ BfTypedValue BfExprEvaluator::ResolveArgValue(BfResolvedArg& resolvedArg, BfType
 					if ((mDeferScopeAlloc != NULL) && (wantType == mModule->mContext->mBfObjectType))
 					{
 						BfAllocTarget allocTarget(mDeferScopeAlloc);
-						argValue = mModule->BoxValue(expr, argValue, wantType, allocTarget);
+						argValue = mModule->BoxValue(expr, argValue, wantType, allocTarget, ((mBfEvalExprFlags & BfEvalExprFlags_Comptime) != 0) ? BfCastFlags_WantsConst : BfCastFlags_None);
 					}
 					else
-						argValue = mModule->Cast(expr, argValue, wantType);
+						argValue = mModule->Cast(expr, argValue, wantType, ((mBfEvalExprFlags & BfEvalExprFlags_Comptime) != 0) ? BfCastFlags_WantsConst : BfCastFlags_None);
 				}
 			}
 		}

+ 30 - 1
IDEHelper/Compiler/BfIRBuilder.cpp

@@ -892,6 +892,24 @@ BfIRValue BfIRConstHolder::CreateConstBitCast(BfIRValue val, BfIRType type)
 	return castedVal;
 }
 
+BfIRValue BfIRConstHolder::CreateConstBox(BfIRValue val, BfIRType type)
+{
+	auto constVal = GetConstant(val);
+
+	auto box = mTempAlloc.Alloc<BfConstantBox>();	
+	box->mConstType = BfConstType_Box;
+	BF_ASSERT(val.mId != -1);
+	box->mTarget = val.mId;
+	box->mToType = type;
+
+	BfIRValue castedVal(BfIRValueFlags_Const, mTempAlloc.GetChunkedId(box));
+#ifdef CHECK_CONSTHOLDER
+	castedVal.mHolder = this;
+#endif
+	BF_ASSERT((void*)GetConstant(castedVal) == (void*)box);
+	return castedVal;
+}
+
 BfIRValue BfIRConstHolder::CreateTypeOf(BfType* type)
 {
 	BfTypeOf_Const* typeOf = mTempAlloc.Alloc<BfTypeOf_Const>();
@@ -1633,7 +1651,13 @@ String BfIRBuilder::ToString(BfIRValue irValue)
 		{
 			auto bitcast = (BfConstantBitCast*)constant;
 			BfIRValue targetConst(BfIRValueFlags_Const, bitcast->mTarget);
-			return ToString(targetConst) + " BitCast to " + ToString(bitcast->mToType);			
+			return ToString(targetConst) + " BitCast to " + ToString(bitcast->mToType);
+		}
+		else if (constant->mConstType == BfConstType_Box)
+		{
+			auto box = (BfConstantBox*)constant;
+			BfIRValue targetConst(BfIRValueFlags_Const, box->mTarget);
+			return ToString(targetConst) + " box to " + ToString(box->mToType);
 		}
 		else if (constant->mConstType == BfConstType_GEP32_2)
 		{
@@ -1825,6 +1849,11 @@ String BfIRBuilder::ToString(BfIRType irType)
 	{
 		return StrFormat("TypeInstPtr#%d:%s", irType.mId, mModule->TypeToString(mModule->mContext->mTypes[irType.mId]).c_str());
 	}
+	else if (irType.mKind == BfIRTypeData::TypeKind_SizedArray)
+	{
+		auto sizedArrayType = (BfConstantSizedArrayType*)GetConstantById(irType.mId);
+		return StrFormat("%s[%d]", ToString(sizedArrayType->mType).c_str(), (int)sizedArrayType->mLength);
+	}
 	else
 	{
 		return "Type ???";

+ 10 - 1
IDEHelper/Compiler/BfIRBuilder.h

@@ -138,7 +138,8 @@ enum BfConstType
 	BfConstType_ArrayZero,
 	BfConstType_ArrayZero8,
 	BfConstType_Undef,
-	BfConstType_SizedArrayType
+	BfConstType_SizedArrayType,
+	BfConstType_Box
 };
 
 enum BfIRValueFlags : uint8
@@ -856,6 +857,13 @@ struct BfConstantBitCast
 	BfIRType mToType;
 };
 
+struct BfConstantBox
+{
+	BfConstType mConstType;
+	int mTarget;
+	BfIRType mToType;
+};
+
 struct BfConstantPtrToInt
 {
 	BfConstType mConstType;
@@ -946,6 +954,7 @@ public:
 	BfIRValue CreateConstArrayZero(BfIRType type, int count);
 	BfIRValue CreateConstArrayZero(int count);
 	BfIRValue CreateConstBitCast(BfIRValue val, BfIRType type);
+	BfIRValue CreateConstBox(BfIRValue val, BfIRType type);
 	BfIRValue CreateTypeOf(BfType* type);
 	BfIRValue CreateTypeOf(BfType* type, BfIRValue typeData);
 	BfIRValue GetUndefConstValue(BfIRType type);	

+ 9 - 12
IDEHelper/Compiler/BfModule.cpp

@@ -240,13 +240,6 @@ void BfMethodState::LocalDefined(BfLocalVariable* localVar, int fieldIdx, BfLoca
 	{
 		return;
 	}
-	//BF_ASSERT(localVarMethodState == this);
-
-//  	if (assignKind == BfLocalVarAssignKind_None)
-//  		assignKind = ((localVarMethodState->mLeftBlockCond) && ((mDeferredLocalAssignData != NULL) || isFromDeferredAssignData))  ? BfLocalVarAssignKind_Conditional : BfLocalVarAssignKind_Unconditional;
-// 	
-// 	//assignKind = BfLocalVarAssignKind_Unconditional;
-
 	
 	if (localVar->mAssignedKind == BfLocalVarAssignKind_None)
 	{
@@ -10108,8 +10101,9 @@ void BfModule::EmitDynamicCastCheck(BfTypedValue typedVal, BfType* type, bool al
 BfTypedValue BfModule::BoxValue(BfAstNode* srcNode, BfTypedValue typedVal, BfType* toType, const BfAllocTarget& allocTarget, BfCastFlags castFlags)
 {
 	bool callDtor = (castFlags & BfCastFlags_NoBoxDtor) == 0;
-
-	if (mBfIRBuilder->mIgnoreWrites)
+	bool wantConst = ((castFlags & BfCastFlags_WantsConst) != 0) && (typedVal.mValue.IsConst());
+	
+	if ((mBfIRBuilder->mIgnoreWrites) && (!wantConst))
 	{
 		if (toType == mContext->mBfObjectType)
 			return BfTypedValue(mBfIRBuilder->GetFakeVal(), toType);
@@ -10241,12 +10235,15 @@ BfTypedValue BfModule::BoxValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
 	
 	if ((toType == NULL) || (toType == mContext->mBfObjectType) || (isBoxedType) || (alreadyCheckedCast) ||  (TypeIsSubTypeOf(fromStructTypeInstance, toTypeInstance)))
 	{
-		if (mBfIRBuilder->mIgnoreWrites)
+		if ((mBfIRBuilder->mIgnoreWrites) && (!wantConst))
 			return BfTypedValue(mBfIRBuilder->GetFakeVal(), (toType != NULL) ? toType : CreateBoxedType(typedVal.mType));
 
-		auto boxedType = CreateBoxedType(typedVal.mType);
-
+		auto boxedType = CreateBoxedType(typedVal.mType);				
 		mBfIRBuilder->PopulateType(boxedType);
+
+		if (wantConst)
+			return BfTypedValue(mBfIRBuilder->CreateConstBox(typedVal.mValue, mBfIRBuilder->MapType(boxedType)), boxedType);
+
 		AddDependency(boxedType, mCurTypeInstance, BfDependencyMap::DependencyFlag_ReadFields);
 		auto allocaInst = AllocFromType(boxedType, allocTarget, BfIRValue(), BfIRValue(), 0, callDtor ? BfAllocFlags_None : BfAllocFlags_NoDtorCall);
 		

+ 2 - 0
IDEHelper/Compiler/BfReducer.cpp

@@ -5680,6 +5680,7 @@ BfStatement* BfReducer::CreateAttributedStatement(BfTokenNode* tokenNode)
  		if ((checkNode->IsA<BfObjectCreateExpression>()) ||
  			(checkNode->IsA<BfInvocationExpression>()) ||
  			(checkNode->IsA<BfVariableDeclaration>()) ||
+			(checkNode->IsA<BfStringInterpolationExpression>()) ||
  			(checkNode->IsA<BfBlock>()))
 		{
 			BfAttributedStatement* attribStmt = mAlloc->Alloc<BfAttributedStatement>();
@@ -5723,6 +5724,7 @@ BfExpression* BfReducer::CreateAttributedExpression(BfTokenNode* tokenNode, bool
 			if ((expr->IsA<BfObjectCreateExpression>()) ||
 				(expr->IsA<BfInvocationExpression>()) ||
 				(expr->IsA<BfVariableDeclaration>()) ||
+				(expr->IsA<BfStringInterpolationExpression>()) ||
 				(expr->IsA<BfBlock>()))
 			{
 				BfAttributedExpression* attribExpr = mAlloc->Alloc<BfAttributedExpression>();

+ 68 - 13
IDEHelper/Compiler/CeMachine.cpp

@@ -3340,6 +3340,13 @@ BfType* CeContext::GetBfType(int typeId)
 	return NULL;
 }
 
+BfType* CeContext::GetBfType(BfIRType irType)
+{
+	if (irType.mKind == BfIRTypeData::TypeKind_TypeId)
+		return GetBfType(irType.mId);
+	return NULL;
+}
+
 void CeContext::PrepareConstStructEntry(CeConstStructData& constEntry)
 {
 	if (constEntry.mHash.IsZero())
@@ -3478,7 +3485,9 @@ bool CeContext::GetCustomAttribute(BfCustomAttributes* customAttributes, int att
 #define CE_GETC(T) *(T*)(mMemory.mVals + addr)
 
 bool CeContext::WriteConstant(BfModule* module, addr_ce addr, BfConstant* constant, BfType* type, bool isParams)
-{	
+{
+	int ptrSize = mCeMachine->mCeModule->mSystem->mPtrSize;
+
 	switch (constant->mTypeCode)
 	{
 	case BfTypeCode_Int8:
@@ -3502,7 +3511,7 @@ bool CeContext::WriteConstant(BfModule* module, addr_ce addr, BfConstant* consta
 		CE_GETC(int64) = constant->mInt64;
 		return true;
 	case BfTypeCode_NullPtr:
-		if (mCeMachine->mCeModule->mSystem->mPtrSize == 4)
+		if (ptrSize == 4)
 			CE_GETC(int32) = 0;
 		else
 			CE_GETC(int64) = 0;
@@ -3522,7 +3531,7 @@ bool CeContext::WriteConstant(BfModule* module, addr_ce addr, BfConstant* consta
 			auto elementType = type->GetUnderlyingType();
 			auto toPtr = CeMalloc(elementType->mSize);
 			addr_ce toAddr = (addr_ce)(toPtr - mMemory.mVals);
-			if (mCeMachine->mCeModule->mSystem->mPtrSize == 4)
+			if (ptrSize == 4)
 				CE_GETC(int32) = (int32)toAddr;
 			else
 				CE_GETC(int64) = (int64)toAddr;
@@ -3560,7 +3569,7 @@ bool CeContext::WriteConstant(BfModule* module, addr_ce addr, BfConstant* consta
 					return false;
 			}
 			
-			if (mCeMachine->mCeModule->mSystem->mPtrSize == 4)
+			if (ptrSize == 4)
 				CE_GETC(int32) = arrayAddr;
 			else
 				CE_GETC(int64) = arrayAddr;
@@ -3581,7 +3590,7 @@ bool CeContext::WriteConstant(BfModule* module, addr_ce addr, BfConstant* consta
 					return false;
 			}
 
-			if (mCeMachine->mCeModule->mSystem->mPtrSize == 4)
+			if (ptrSize == 4)
 			{
 				CE_GETC(int32) = elemsAddr;
 				addr += 4;
@@ -3662,7 +3671,7 @@ bool CeContext::WriteConstant(BfModule* module, addr_ce addr, BfConstant* consta
 
 		if (type->IsPointer())
 		{						
-			if (mCeMachine->mCeModule->mSystem->mPtrSize == 4)
+			if (ptrSize == 4)
 				CE_GETC(int32) = constAggData->mCEAddr;
 			else
 				CE_GETC(int64) = constAggData->mCEAddr;
@@ -3678,11 +3687,38 @@ bool CeContext::WriteConstant(BfModule* module, addr_ce addr, BfConstant* consta
 	if (constant->mConstType == BfConstType_BitCast)
 	{
 		auto constBitCast = (BfConstantBitCast*)constant;
-
 		auto constTarget = module->mBfIRBuilder->GetConstantById(constBitCast->mTarget);
 		return WriteConstant(module, addr, constTarget, type);
 	}
 
+	if (constant->mConstType == BfConstType_Box)
+	{
+		auto constBox = (BfConstantBox*)constant;		
+		auto boxedType = GetBfType(constBox->mToType);
+		if (boxedType == NULL)
+			return false;
+		auto boxedTypeInst = boxedType->ToTypeInstance();
+		if (boxedTypeInst == NULL)
+			return false;
+		module->PopulateType(boxedTypeInst);
+		if (boxedTypeInst->mFieldInstances.IsEmpty())
+			return false;
+		auto& fieldInstance = boxedTypeInst->mFieldInstances.back();
+
+		auto boxedMem = CeMalloc(boxedTypeInst->mInstSize);
+		memset(boxedMem, 0, ptrSize*2);		
+		*(int32*)boxedMem = boxedTypeInst->mTypeId;
+
+		auto constTarget = module->mBfIRBuilder->GetConstantById(constBox->mTarget);
+		WriteConstant(module, boxedMem - mMemory.mVals + fieldInstance.mDataOffset, constTarget, fieldInstance.mResolvedType);
+
+		if (ptrSize == 4)
+			CE_GETC(int32) = (int32)(boxedMem - mMemory.mVals);
+		else
+			CE_GETC(int64) = (int64)(boxedMem - mMemory.mVals);
+		return true;
+	}
+
 	if (constant->mConstType == BfConstType_PtrToInt)
 	{
 		auto ptrToIntConst = (BfConstantPtrToInt*)constant;		
@@ -3711,7 +3747,7 @@ bool CeContext::WriteConstant(BfModule* module, addr_ce addr, BfConstant* consta
 
 				int stringId = atoi(globalVar->mName + 11);
 				addr_ce strAddr = GetString(stringId) + stringTypeInst->mInstSize;
-				if (mCeMachine->mCeModule->mSystem->mPtrSize == 4)
+				if (ptrSize == 4)
 					CE_GETC(int32) = strAddr;
 				else
 					CE_GETC(int64) = strAddr;
@@ -3727,7 +3763,7 @@ bool CeContext::WriteConstant(BfModule* module, addr_ce addr, BfConstant* consta
 		{
 			int stringId = atoi(globalVar->mName  + 10);
 			addr_ce strAddr = GetString(stringId);			
-			if (mCeMachine->mCeModule->mSystem->mPtrSize == 4)
+			if (ptrSize == 4)
 				CE_GETC(int32) = strAddr;
 			else
 				CE_GETC(int64) = strAddr;
@@ -3745,7 +3781,7 @@ bool CeContext::WriteConstant(BfModule* module, addr_ce addr, BfConstant* consta
 			strAddr += stringTypeInst->mInstSize;
 		}
 
-		if (mCeMachine->mCeModule->mSystem->mPtrSize == 4)
+		if (ptrSize == 4)
 			CE_GETC(int32) = strAddr;
 		else
 			CE_GETC(int64) = strAddr;
@@ -3756,7 +3792,7 @@ bool CeContext::WriteConstant(BfModule* module, addr_ce addr, BfConstant* consta
 	{
 		auto constTypeOf = (BfTypeOf_Const*)constant;
 		addr_ce typeAddr = GetReflectType(constTypeOf->mType->mTypeId);
-		if (mCeMachine->mCeModule->mSystem->mPtrSize == 4)
+		if (ptrSize == 4)
 			CE_GETC(int32) = typeAddr;
 		else
 			CE_GETC(int64) = typeAddr;
@@ -5392,7 +5428,19 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8*
 				addr_ce strAddr = *(addr_ce*)((uint8*)stackPtr + 4 + 8);
 
 				char str[256];
-				int count = DoubleToString(val, str);				
+				int count = DoubleToString(val, str);
+				CE_CHECKADDR(strAddr, count + 1);
+				memcpy(memStart + strAddr, str, count + 1);
+				result = count;
+			}
+			else if (checkFunction->mFunctionKind == CeFunctionKind_Float_ToString)
+			{
+				int32& result = *(int32*)((uint8*)stackPtr + 0);
+				float val = *(float*)((uint8*)stackPtr + 4);
+				addr_ce strAddr = *(addr_ce*)((uint8*)stackPtr + 4 + 4);
+
+				char str[256];
+				int count = FloatToString(val, str);
 				CE_CHECKADDR(strAddr, count + 1);
 				memcpy(memStart + strAddr, str, count + 1);
 				result = count;
@@ -8174,7 +8222,14 @@ void CeMachine::CheckFunctionKind(CeFunction* ceFunction)
 				else if (methodDef->mName == "ftoa")
 					ceFunction->mFunctionKind = CeFunctionKind_Double_Ftoa;
 				if (methodDef->mName == "ToString")
-					ceFunction->mFunctionKind = CeFunctionKind_Double_ToString;				
+					ceFunction->mFunctionKind = CeFunctionKind_Double_ToString;
+			}
+			else if (owner->IsInstanceOf(mCeModule->mCompiler->mFloatTypeDef))
+			{
+				if (methodDef->mName == "ftoa")
+					ceFunction->mFunctionKind = CeFunctionKind_Double_Ftoa;
+				if (methodDef->mName == "ToString")
+					ceFunction->mFunctionKind = CeFunctionKind_Float_ToString;
 			}
 			else if (owner->IsInstanceOf(mCeModule->mCompiler->mMathTypeDef))
 			{

+ 2 - 0
IDEHelper/Compiler/CeMachine.h

@@ -398,6 +398,7 @@ enum CeFunctionKind
 	CeFunctionKind_Double_Strtod,
 	CeFunctionKind_Double_Ftoa,
 	CeFunctionKind_Double_ToString,
+	CeFunctionKind_Float_ToString,
 
 	CeFunctionKind_Math_Abs,
 	CeFunctionKind_Math_Acos,
@@ -900,6 +901,7 @@ public:
 	addr_ce GetString(const StringImpl& str);
 	addr_ce GetConstantData(BeConstant* constant);
 	BfType* GetBfType(int typeId);
+	BfType* GetBfType(BfIRType irType);
 	void PrepareConstStructEntry(CeConstStructData& constStructData);
 	bool CheckMemory(addr_ce addr, int32 size);
 	bool GetStringFromAddr(addr_ce strInstAddr, StringImpl& str);