aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/StringValueGen.cc
blob: c07f9a98346577d74d8a2e3a71c90635c80398cb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71

#include "cps/CodeGen.h"
#include "cps/Operator.h"

using namespace cps;
using namespace llvm;

const TypeInfo *CodeGen::requireStringType() {
    const TypeInfo *Type = resolveType("STRING");
    if (!Type || !Type->IsClass) {
        reportError("String literals require a visible STRING class; include the string library or omit -no-std");
        return nullptr;
    }
    return Type;
}

Value *CodeGen::emitStringFromCString(Value *Text) {
    const TypeInfo *Type = requireStringType();
    if (!Type || !Text) return nullptr;
    const FuncSig *Constructor = nullptr;
    for (const FuncSig *Sig : FuncGen->getOverloads(Type->Name + ".NEW"))
        if (Sig->Params.size() == 1 && !Sig->Params[0].IsArray && !Sig->Params[0].IsByRef &&
            resolveType("C_STRING")->sameType(resolveType(Sig->Params[0].TypeName)))
            Constructor = Sig;
    if (!Constructor) {
        reportError("STRING requires a constructor NEW(Text : C_STRING)");
        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;
    if (!FuncGen->emitCall(*Constructor, {Storage, Text})) return nullptr;
    // The consumer takes ownership, just as with an ordinary class result.
    return Builder->CreateLoad(Type->LLVMType, Storage, "string");
}

Value *CodeGen::emitStringCString(Value *Value) {
    const TypeInfo *Type = requireStringType();
    if (!Type || !Value) return nullptr;
    const FuncSig *Method = resolveMethod(Type->Name, "C_STR", {});
    if (!Method || !resolveType("C_STRING")->sameType(resolveType(Method->ReturnTypeName))) {
        reportError("STRING requires a method C_STR() RETURNS C_STRING");
        return nullptr;
    }
    auto *Receiver = CreateEntryBlockAlloca(Builder->GetInsertBlock()->getParent(),
                                           Type->LLVMType, "string_view");
    Builder->CreateStore(Value, Receiver);
    return emitMethodCall(Type->Name, Receiver, "C_STR", {}, DiagnosticLine);
}

Value *CodeGen::emitCStringExpr(ExprAST *Expr) {
    const TypeInfo *Type = getExprTypeInfo(Expr);
    if (!Type || !Type->isString() || isWholeArrayVar(Expr)) {
        reportError("Expected a STRING value");
        return nullptr;
    }
    Value *Value = emitExpr(Expr);
    if (!Value) return nullptr;
    if (!isObjectLValue(Expr)) materializeOperatorReceiver(Value, Type);
    return emitStringCString(Value);
}

bool CodeGen::containsString(const TypeInfo *Type) const {
    if (!Type) return false;
    if (Type->isString()) return true;
    if (Type->asRecord())
        for (const auto &[Name, Field] : Type->Record.Fields)
            if (containsString(resolveType(Field.TypeName))) return true;
    return false;
}