diff --git a/BeefLibs/corlib/src/String.bf b/BeefLibs/corlib/src/String.bf index 7e035abb..783dc545 100644 --- a/BeefLibs/corlib/src/String.bf +++ b/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 AppendF(IFormatProvider provider, StringView format, params Object[] args) + public Result AppendF(IFormatProvider provider, StringView format, params Span 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 AppendF(StringView format, params Object[] args) + public Result AppendF(StringView format, params Span 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 args) + { + return new String()..AppendF(format, params args); + } + public static bool Equals(char8* str1, char8* str2) { for (int i = 0; true; i++) diff --git a/IDEHelper/Compiler/BfCompiler.cpp b/IDEHelper/Compiler/BfCompiler.cpp index 2c9fc4c0..eec6b4c9 100644 --- a/IDEHelper/Compiler/BfCompiler.cpp +++ b/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"); diff --git a/IDEHelper/Compiler/BfCompiler.h b/IDEHelper/Compiler/BfCompiler.h index 89d4d3d7..5ddcb5e5 100644 --- a/IDEHelper/Compiler/BfCompiler.h +++ b/IDEHelper/Compiler/BfCompiler.h @@ -347,6 +347,7 @@ public: BfTypeDef* mBfObjectTypeDef; BfTypeDef* mChar32TypeDef; + BfTypeDef* mFloatTypeDef; BfTypeDef* mDoubleTypeDef; BfTypeDef* mMathTypeDef; diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index e4e5865c..0de3463c 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/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 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 argExprs; + argExprs.Add(stringInterpolationExpression); + BfSizedArray 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); } } } diff --git a/IDEHelper/Compiler/BfIRBuilder.cpp b/IDEHelper/Compiler/BfIRBuilder.cpp index ecea0415..6cc82fd8 100644 --- a/IDEHelper/Compiler/BfIRBuilder.cpp +++ b/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(); + 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(); @@ -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 ???"; diff --git a/IDEHelper/Compiler/BfIRBuilder.h b/IDEHelper/Compiler/BfIRBuilder.h index 418606fb..15a7f03b 100644 --- a/IDEHelper/Compiler/BfIRBuilder.h +++ b/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); diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 0017c052..1cac4bb3 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/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); diff --git a/IDEHelper/Compiler/BfReducer.cpp b/IDEHelper/Compiler/BfReducer.cpp index 5a312208..4f923bb7 100644 --- a/IDEHelper/Compiler/BfReducer.cpp +++ b/IDEHelper/Compiler/BfReducer.cpp @@ -5680,6 +5680,7 @@ BfStatement* BfReducer::CreateAttributedStatement(BfTokenNode* tokenNode) if ((checkNode->IsA()) || (checkNode->IsA()) || (checkNode->IsA()) || + (checkNode->IsA()) || (checkNode->IsA())) { BfAttributedStatement* attribStmt = mAlloc->Alloc(); @@ -5723,6 +5724,7 @@ BfExpression* BfReducer::CreateAttributedExpression(BfTokenNode* tokenNode, bool if ((expr->IsA()) || (expr->IsA()) || (expr->IsA()) || + (expr->IsA()) || (expr->IsA())) { BfAttributedExpression* attribExpr = mAlloc->Alloc(); diff --git a/IDEHelper/Compiler/CeMachine.cpp b/IDEHelper/Compiler/CeMachine.cpp index 7886128e..78c69a09 100644 --- a/IDEHelper/Compiler/CeMachine.cpp +++ b/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)) { diff --git a/IDEHelper/Compiler/CeMachine.h b/IDEHelper/Compiler/CeMachine.h index 97d0e46c..61aedcc8 100644 --- a/IDEHelper/Compiler/CeMachine.h +++ b/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);