1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 11:38:21 +02:00

Const string interpolation

This commit is contained in:
Brian Fiete 2022-02-13 10:41:34 -05:00
parent f38cf6a1fd
commit 8ebd7516d8
10 changed files with 167 additions and 40 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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