diff options
Diffstat (limited to 'lib/CodeGen/StringValueGen.cc')
| -rw-r--r-- | lib/CodeGen/StringValueGen.cc | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/lib/CodeGen/StringValueGen.cc b/lib/CodeGen/StringValueGen.cc index c07f9a9..989bac8 100644 --- a/lib/CodeGen/StringValueGen.cc +++ b/lib/CodeGen/StringValueGen.cc @@ -35,6 +35,57 @@ Value *CodeGen::emitStringFromCString(Value *Text) { return Builder->CreateLoad(Type->LLVMType, Storage, "string"); } +// CHAR -> STRING: STRING.NEW(1, ch). +Value *CodeGen::emitStringFromChar(Value *Ch) { + const TypeInfo *Type = requireStringType(); + if (!Type || !Ch) return nullptr; + const TypeInfo *CChar = resolveType("C_CHAR"); + const FuncSig *Constructor = nullptr; + for (const FuncSig *Sig : FuncGen->getOverloads(Type->Name + ".NEW")) + if (Sig->Params.size() == 2 && !Sig->Params[1].IsArray && !Sig->Params[1].IsByRef && + CChar->sameType(resolveType(Sig->Params[1].TypeName))) + Constructor = Sig; + if (!Constructor) { + reportError("STRING requires a constructor NEW(Count : INTEGER, Ch : C_CHAR)"); + return nullptr; + } + if (!checkOperatorAccess(*Constructor)) return nullptr; + auto *Storage = CreateEntryBlockAlloca(Builder->GetInsertBlock()->getParent(), + Type->LLVMType, "string_value"); + Builder->CreateStore(Types->getZeroValue(Type->Name), Storage); + if (!emitFieldDefaults(Type, Storage, DiagnosticLine)) return nullptr; + Value *Count = ConstantInt::get(resolveType("INTEGER")->LLVMType, 1); + if (!FuncGen->emitCall(*Constructor, {Storage, Count, Ch})) return nullptr; + // The consumer takes ownership, just as with an ordinary class result. + return Builder->CreateLoad(Type->LLVMType, Storage, "string"); +} + +// STRING -> CHAR: the string must hold exactly one character. +Value *CodeGen::emitCharFromString(ExprAST *Expr, int Line) { + const TypeInfo *Type = requireStringType(); + if (!Type) return nullptr; + Value *Text = emitExpr(Expr); + if (!Text) return nullptr; + if (!isObjectLValue(Expr)) materializeOperatorReceiver(Text, Type); + auto *Receiver = CreateEntryBlockAlloca(Builder->GetInsertBlock()->getParent(), + Type->LLVMType, "string_view"); + Builder->CreateStore(Text, Receiver); + const FuncSig *Method = resolveMethod(Type->Name, "_LENGTH", {}); + if (!Method || !resolveType("INTEGER")->sameType(resolveType(Method->ReturnTypeName))) { + reportError("STRING requires a method _LENGTH() RETURNS INTEGER"); + return nullptr; + } + Value *Length = emitMethodCall(Type->Name, Receiver, "_LENGTH", {}, Line); + if (!Length) return nullptr; + Value *Wrong = Builder->CreateICmpNE(Length, ConstantInt::get(Length->getType(), 1), "char_len_bad"); + Value *Msg = Builder->CreateGlobalString("[Fatal] line %d: STRING of length %lld cannot be converted to CHAR\n", + "err_string_to_char", 0, TheModule.get()); + RuntimeChecker->emitCheck(Wrong, Msg, {RuntimeChecker->lineValue(Line), Length}); + Value *Ptr = emitMethodCall(Type->Name, Receiver, "C_STR", {}, Line); + if (!Ptr) return nullptr; + return Builder->CreateLoad(resolveType("CHAR")->LLVMType, Ptr, "char_value"); +} + Value *CodeGen::emitStringCString(Value *Value) { const TypeInfo *Type = requireStringType(); if (!Type || !Value) return nullptr; |
