From f850bcc7502701df04f169a3acd8baf08b3f872a Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Mon, 5 May 2025 13:44:43 +0200
Subject: [PATCH 01/79] Remove llvmprocedure.h

---
 src/engine/internal/llvm/CMakeLists.txt  |  1 -
 src/engine/internal/llvm/llvmprocedure.h | 14 --------------
 2 files changed, 15 deletions(-)
 delete mode 100644 src/engine/internal/llvm/llvmprocedure.h

diff --git a/src/engine/internal/llvm/CMakeLists.txt b/src/engine/internal/llvm/CMakeLists.txt
index 01520d08..1b0a3176 100644
--- a/src/engine/internal/llvm/CMakeLists.txt
+++ b/src/engine/internal/llvm/CMakeLists.txt
@@ -11,7 +11,6 @@ target_sources(scratchcpp
     llvmcoroutine.h
     llvmvariableptr.h
     llvmlistptr.h
-    llvmprocedure.h
     llvmtypes.cpp
     llvmtypes.h
     llvmfunctions.cpp
diff --git a/src/engine/internal/llvm/llvmprocedure.h b/src/engine/internal/llvm/llvmprocedure.h
deleted file mode 100644
index 7cb57679..00000000
--- a/src/engine/internal/llvm/llvmprocedure.h
+++ /dev/null
@@ -1,14 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-
-#pragma once
-
-namespace libscratchcpp
-{
-
-struct LLVMProcedure
-{
-        // TODO: Implement procedures
-        bool warp = false;
-};
-
-} // namespace libscratchcpp

From de624f17b6559d03f2b46a75c518efe8aca590ba Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Tue, 22 Jul 2025 18:24:23 +0200
Subject: [PATCH 02/79] LLVMCodeBuilder: Mark m_instruction as deprecated

This variable will become obsolete after we switch to linked list.
---
 src/engine/internal/llvm/llvmcodebuilder.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/engine/internal/llvm/llvmcodebuilder.h b/src/engine/internal/llvm/llvmcodebuilder.h
index 68bb517e..cc533b68 100644
--- a/src/engine/internal/llvm/llvmcodebuilder.h
+++ b/src/engine/internal/llvm/llvmcodebuilder.h
@@ -234,7 +234,7 @@ class LLVMCodeBuilder : public ICodeBuilder
         llvm::StructType *m_stringPtrType = nullptr;
         llvm::FunctionType *m_resumeFuncType = nullptr;
 
-        std::vector<std::shared_ptr<LLVMInstruction>> m_instructions;
+        [[deprecated]] std::vector<std::shared_ptr<LLVMInstruction>> m_instructions; // TODO: Remove this
         std::vector<std::shared_ptr<LLVMRegister>> m_regs;
         std::vector<std::shared_ptr<CompilerLocalVariable>> m_localVars;
         LLVMRegister *m_lastConstValue = nullptr; // for reporters and hat predicates

From 6330ed6fea3747a8b48fb59040875928d54252f2 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Tue, 22 Jul 2025 19:14:53 +0200
Subject: [PATCH 03/79] Add LLVMInstructionList class

---
 src/engine/internal/llvm/CMakeLists.txt       |   2 +
 src/engine/internal/llvm/llvminstruction.h    |   4 +
 .../internal/llvm/llvminstructionlist.cpp     |  35 ++++
 .../internal/llvm/llvminstructionlist.h       |  28 +++
 test/llvm/CMakeLists.txt                      |   1 +
 test/llvm/llvminstructionlist_test.cpp        | 182 ++++++++++++++++++
 6 files changed, 252 insertions(+)
 create mode 100644 src/engine/internal/llvm/llvminstructionlist.cpp
 create mode 100644 src/engine/internal/llvm/llvminstructionlist.h
 create mode 100644 test/llvm/llvminstructionlist_test.cpp

diff --git a/src/engine/internal/llvm/CMakeLists.txt b/src/engine/internal/llvm/CMakeLists.txt
index 1b0a3176..3fcb3d79 100644
--- a/src/engine/internal/llvm/CMakeLists.txt
+++ b/src/engine/internal/llvm/CMakeLists.txt
@@ -5,6 +5,8 @@ target_sources(scratchcpp
     llvmregister.h
     llvmconstantregister.h
     llvminstruction.h
+    llvminstructionlist.cpp
+    llvminstructionlist.h
     llvmifstatement.h
     llvmloop.h
     llvmcoroutine.cpp
diff --git a/src/engine/internal/llvm/llvminstruction.h b/src/engine/internal/llvm/llvminstruction.h
index 11c6ad31..1116b347 100644
--- a/src/engine/internal/llvm/llvminstruction.h
+++ b/src/engine/internal/llvm/llvminstruction.h
@@ -100,6 +100,10 @@ struct LLVMInstruction
         size_t procedureArgIndex = 0;
         LLVMLoopScope *loopScope = nullptr;
         bool loopCondition = false; // whether the instruction is part of a loop condition
+
+        // Linked list
+        LLVMInstruction *previous = nullptr;
+        LLVMInstruction *next = nullptr;
 };
 
 } // namespace libscratchcpp
diff --git a/src/engine/internal/llvm/llvminstructionlist.cpp b/src/engine/internal/llvm/llvminstructionlist.cpp
new file mode 100644
index 00000000..1f4fbe6a
--- /dev/null
+++ b/src/engine/internal/llvm/llvminstructionlist.cpp
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#include <cassert>
+
+#include "llvminstructionlist.h"
+#include "llvminstruction.h"
+
+using namespace libscratchcpp;
+
+LLVMInstruction *LLVMInstructionList::first()
+{
+    return m_first.get();
+}
+
+LLVMInstruction *LLVMInstructionList::last()
+{
+    return m_last.get();
+}
+
+void LLVMInstructionList::addInstruction(std::shared_ptr<LLVMInstruction> ins)
+{
+    if (!(m_first && m_last)) {
+        assert(!m_first && !m_last);
+
+        m_first = ins;
+        m_last = ins;
+
+        ins->previous = nullptr;
+        ins->next = nullptr;
+    } else {
+        m_last->next = ins.get();
+        ins->previous = m_last.get();
+        m_last = ins;
+    }
+}
diff --git a/src/engine/internal/llvm/llvminstructionlist.h b/src/engine/internal/llvm/llvminstructionlist.h
new file mode 100644
index 00000000..82036555
--- /dev/null
+++ b/src/engine/internal/llvm/llvminstructionlist.h
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include <memory>
+
+namespace libscratchcpp
+{
+
+struct LLVMInstruction;
+
+class LLVMInstructionList
+{
+    public:
+        LLVMInstructionList() = default;
+        LLVMInstructionList(const LLVMInstructionList &) = delete;
+
+        LLVMInstruction *first();
+        LLVMInstruction *last();
+
+        void addInstruction(std::shared_ptr<LLVMInstruction> ins);
+
+    private:
+        std::shared_ptr<LLVMInstruction> m_first;
+        std::shared_ptr<LLVMInstruction> m_last;
+};
+
+} // namespace libscratchcpp
diff --git a/test/llvm/CMakeLists.txt b/test/llvm/CMakeLists.txt
index abfc4d98..02337d23 100644
--- a/test/llvm/CMakeLists.txt
+++ b/test/llvm/CMakeLists.txt
@@ -19,6 +19,7 @@ add_executable(
   llvmexecutioncontext_test.cpp
   llvmexecutablecode_test.cpp
   llvmcodebuilder_test.cpp
+  llvminstructionlist_test.cpp
 )
 
 target_link_libraries(
diff --git a/test/llvm/llvminstructionlist_test.cpp b/test/llvm/llvminstructionlist_test.cpp
new file mode 100644
index 00000000..ec585179
--- /dev/null
+++ b/test/llvm/llvminstructionlist_test.cpp
@@ -0,0 +1,182 @@
+#include <scratchcpp/thread.h>
+#include <engine/internal/llvm/llvminstructionlist.h>
+#include <engine/internal/llvm/llvminstruction.h>
+#include <gtest/gtest.h>
+
+using namespace libscratchcpp;
+
+TEST(LLVMInstructionListTest, EmptyList_First)
+{
+    LLVMInstructionList list;
+    ASSERT_EQ(list.first(), nullptr);
+}
+
+TEST(LLVMInstructionListTest, EmptyList_Last)
+{
+    LLVMInstructionList list;
+    ASSERT_EQ(list.last(), nullptr);
+}
+
+TEST(LLVMInstructionListTest, AddSingleInstruction_First)
+{
+    LLVMInstructionList list;
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins);
+
+    ASSERT_EQ(list.first(), ins.get());
+}
+
+TEST(LLVMInstructionListTest, AddSingleInstruction_Last)
+{
+    LLVMInstructionList list;
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins);
+
+    ASSERT_EQ(list.last(), ins.get());
+}
+
+TEST(LLVMInstructionListTest, AddSingleInstruction_Previous)
+{
+    LLVMInstructionList list;
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins);
+
+    ASSERT_EQ(ins->previous, nullptr);
+}
+
+TEST(LLVMInstructionListTest, AddSingleInstruction_Next)
+{
+    LLVMInstructionList list;
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins);
+
+    ASSERT_EQ(ins->next, nullptr);
+}
+
+TEST(LLVMInstructionListTest, AddMultipleInstructions_First)
+{
+    LLVMInstructionList list;
+
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins1);
+
+    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins2);
+
+    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins3);
+
+    ASSERT_EQ(list.first(), ins1.get());
+}
+
+TEST(LLVMInstructionListTest, AddMultipleInstructions_Last)
+{
+    LLVMInstructionList list;
+
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins1);
+
+    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins2);
+
+    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins3);
+
+    ASSERT_EQ(list.last(), ins3.get());
+}
+
+TEST(LLVMInstructionListTest, AddMultipleInstructions_PreviousOfFirst)
+{
+    LLVMInstructionList list;
+
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins1);
+
+    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins2);
+
+    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins3);
+
+    ASSERT_EQ(ins1->previous, nullptr);
+}
+
+TEST(LLVMInstructionListTest, AddMultipleInstructions_NextOfFirst)
+{
+    LLVMInstructionList list;
+
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins1);
+
+    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins2);
+
+    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins3);
+
+    ASSERT_EQ(ins1->next, ins2.get());
+}
+
+TEST(LLVMInstructionListTest, AddMultipleInstructions_PreviousOfMiddle)
+{
+    LLVMInstructionList list;
+
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins1);
+
+    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins2);
+
+    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins3);
+
+    ASSERT_EQ(ins2->previous, ins1.get());
+}
+
+TEST(LLVMInstructionListTest, AddMultipleInstructions_NextOfMiddle)
+{
+    LLVMInstructionList list;
+
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins1);
+
+    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins2);
+
+    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins3);
+
+    ASSERT_EQ(ins2->next, ins3.get());
+}
+
+TEST(LLVMInstructionListTest, AddMultipleInstructions_PreviousOfLast)
+{
+    LLVMInstructionList list;
+
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins1);
+
+    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins2);
+
+    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins3);
+
+    ASSERT_EQ(ins3->previous, ins2.get());
+}
+
+TEST(LLVMInstructionListTest, AddMultipleInstructions_NextOfLast)
+{
+    LLVMInstructionList list;
+
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins1);
+
+    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins2);
+
+    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins3);
+
+    ASSERT_EQ(ins3->next, nullptr);
+}

From 142e7e563f03d976ff77c24cc69d7677f370ec40 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Tue, 22 Jul 2025 19:17:01 +0200
Subject: [PATCH 04/79] LLVMCodeBuilder: Rename m_instructions

---
 src/engine/internal/llvm/llvmcodebuilder.cpp | 80 ++++++++++----------
 src/engine/internal/llvm/llvmcodebuilder.h   |  2 +-
 2 files changed, 41 insertions(+), 41 deletions(-)

diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp
index e0e44e72..ac8039fc 100644
--- a/src/engine/internal/llvm/llvmcodebuilder.cpp
+++ b/src/engine/internal/llvm/llvmcodebuilder.cpp
@@ -53,11 +53,11 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 {
     if (!m_warp) {
         // Do not create coroutine if there are no yield instructions nor non-warp procedure calls
-        auto it = std::find_if(m_instructions.begin(), m_instructions.end(), [](const std::shared_ptr<LLVMInstruction> &step) {
+        auto it = std::find_if(m_instructionList.begin(), m_instructionList.end(), [](const std::shared_ptr<LLVMInstruction> &step) {
             return step->type == LLVMInstruction::Type::Yield || (step->type == LLVMInstruction::Type::CallProcedure && step->procedurePrototype && !step->procedurePrototype->warp());
         });
 
-        if (it == m_instructions.end())
+        if (it == m_instructionList.end())
             m_warp = true;
 
         // Only create coroutines in scripts
@@ -153,7 +153,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
     pushScopeLevel();
 
     // Execute recorded steps
-    for (const auto insPtr : m_instructions) {
+    for (const auto insPtr : m_instructionList) {
         const LLVMInstruction &step = *insPtr;
 
         switch (step.type) {
@@ -1340,8 +1340,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
         case Compiler::CodeType::Reporter: {
             // Use last instruction return value (or last constant) and create a ValueData instance
-            assert(!m_instructions.empty() || m_lastConstValue);
-            LLVMRegister *ret = m_instructions.empty() ? m_lastConstValue : m_instructions.back()->functionReturnReg;
+            assert(!m_instructionList.empty() || m_lastConstValue);
+            LLVMRegister *ret = m_instructionList.empty() ? m_lastConstValue : m_instructionList.back()->functionReturnReg;
             llvm::Value *copy = createNewValue(ret);
             m_builder.CreateRet(m_builder.CreateLoad(m_valueDataType, copy));
             break;
@@ -1349,12 +1349,12 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
         case Compiler::CodeType::HatPredicate:
             // Use last instruction return value (or last constant)
-            assert(!m_instructions.empty() || m_lastConstValue);
+            assert(!m_instructionList.empty() || m_lastConstValue);
 
-            if (m_instructions.empty())
+            if (m_instructionList.empty())
                 m_builder.CreateRet(castValue(m_lastConstValue, Compiler::StaticType::Bool));
             else
-                m_builder.CreateRet(castValue(m_instructions.back()->functionReturnReg, Compiler::StaticType::Bool));
+                m_builder.CreateRet(castValue(m_instructionList.back()->functionReturnReg, Compiler::StaticType::Bool));
             break;
     }
 
@@ -1394,25 +1394,25 @@ CompilerValue *LLVMCodeBuilder::addFunctionCall(const std::string &functionName,
         auto reg = std::make_shared<LLVMRegister>(returnType);
         reg->isRawValue = true;
         ins->functionReturnReg = reg.get();
-        m_instructions.push_back(ins);
+        m_instructionList.push_back(ins);
         return addReg(reg, ins);
     }
 
-    m_instructions.push_back(ins);
+    m_instructionList.push_back(ins);
     return nullptr;
 }
 
 CompilerValue *LLVMCodeBuilder::addTargetFunctionCall(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args)
 {
     CompilerValue *ret = addFunctionCall(functionName, returnType, argTypes, args);
-    m_instructions.back()->functionTargetArg = true;
+    m_instructionList.back()->functionTargetArg = true;
     return ret;
 }
 
 CompilerValue *LLVMCodeBuilder::addFunctionCallWithCtx(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args)
 {
     CompilerValue *ret = addFunctionCall(functionName, returnType, argTypes, args);
-    m_instructions.back()->functionCtxArg = true;
+    m_instructionList.back()->functionCtxArg = true;
     return ret;
 }
 
@@ -1456,8 +1456,8 @@ CompilerValue *LLVMCodeBuilder::addVariableValue(Variable *variable)
     ret->isRawValue = false;
     ins->functionReturnReg = ret.get();
 
-    m_instructions.push_back(ins);
-    m_variableInstructions.push_back(m_instructions.back());
+    m_instructionList.push_back(ins);
+    m_variableInstructions.push_back(m_instructionList.back());
     return addReg(ret, ins);
 }
 
@@ -1486,8 +1486,8 @@ CompilerValue *LLVMCodeBuilder::addListItem(List *list, CompilerValue *index)
     ret->isRawValue = false;
     ins->functionReturnReg = ret.get();
 
-    m_instructions.push_back(ins);
-    m_listInstructions.push_back(m_instructions.back());
+    m_instructionList.push_back(ins);
+    m_listInstructions.push_back(m_instructionList.back());
     return addReg(ret, ins);
 }
 
@@ -1500,7 +1500,7 @@ CompilerValue *LLVMCodeBuilder::addListItemIndex(List *list, CompilerValue *item
         m_listPtrs[list] = LLVMListPtr();
 
     auto ret = createOp(ins, Compiler::StaticType::Number, Compiler::StaticType::Unknown, { item });
-    m_listInstructions.push_back(m_instructions.back());
+    m_listInstructions.push_back(m_instructionList.back());
     return ret;
 }
 
@@ -1513,7 +1513,7 @@ CompilerValue *LLVMCodeBuilder::addListContains(List *list, CompilerValue *item)
         m_listPtrs[list] = LLVMListPtr();
 
     auto ret = createOp(ins, Compiler::StaticType::Bool, Compiler::StaticType::Unknown, { item });
-    m_listInstructions.push_back(m_instructions.back());
+    m_listInstructions.push_back(m_instructionList.back());
     return ret;
 }
 
@@ -1549,7 +1549,7 @@ CompilerValue *LLVMCodeBuilder::addProcedureArgument(const std::string &name)
     ins->functionReturnReg = ret.get();
     ins->procedureArgIndex = index;
 
-    m_instructions.push_back(ins);
+    m_instructionList.push_back(ins);
     return addReg(ret, ins);
 }
 
@@ -1737,10 +1737,10 @@ void LLVMCodeBuilder::createVariableWrite(Variable *variable, CompilerValue *val
 
     if (m_loopScope >= 0) {
         auto scope = m_loopScopes[m_loopScope];
-        m_variablePtrs[variable].loopVariableWrites[scope.get()].push_back(m_instructions.back());
+        m_variablePtrs[variable].loopVariableWrites[scope.get()].push_back(m_instructionList.back());
     }
 
-    m_variableInstructions.push_back(m_instructions.back());
+    m_variableInstructions.push_back(m_instructionList.back());
 }
 
 void LLVMCodeBuilder::createListClear(List *list)
@@ -1774,10 +1774,10 @@ void LLVMCodeBuilder::createListAppend(List *list, CompilerValue *item)
 
     if (m_loopScope >= 0) {
         auto scope = m_loopScopes[m_loopScope];
-        m_listPtrs[list].loopListWrites[scope.get()].push_back(m_instructions.back());
+        m_listPtrs[list].loopListWrites[scope.get()].push_back(m_instructionList.back());
     }
 
-    m_listInstructions.push_back(m_instructions.back());
+    m_listInstructions.push_back(m_instructionList.back());
 }
 
 void LLVMCodeBuilder::createListInsert(List *list, CompilerValue *index, CompilerValue *item)
@@ -1791,10 +1791,10 @@ void LLVMCodeBuilder::createListInsert(List *list, CompilerValue *index, Compile
 
     if (m_loopScope >= 0) {
         auto scope = m_loopScopes[m_loopScope];
-        m_listPtrs[list].loopListWrites[scope.get()].push_back(m_instructions.back());
+        m_listPtrs[list].loopListWrites[scope.get()].push_back(m_instructionList.back());
     }
 
-    m_listInstructions.push_back(m_instructions.back());
+    m_listInstructions.push_back(m_instructionList.back());
 }
 
 void LLVMCodeBuilder::createListReplace(List *list, CompilerValue *index, CompilerValue *item)
@@ -1808,27 +1808,27 @@ void LLVMCodeBuilder::createListReplace(List *list, CompilerValue *index, Compil
 
     if (m_loopScope >= 0) {
         auto scope = m_loopScopes[m_loopScope];
-        m_listPtrs[list].loopListWrites[scope.get()].push_back(m_instructions.back());
+        m_listPtrs[list].loopListWrites[scope.get()].push_back(m_instructionList.back());
     }
 
-    m_listInstructions.push_back(m_instructions.back());
+    m_listInstructions.push_back(m_instructionList.back());
 }
 
 void LLVMCodeBuilder::beginIfStatement(CompilerValue *cond)
 {
     auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, currentLoopScope(), m_loopCondition);
     ins->args.push_back({ Compiler::StaticType::Bool, dynamic_cast<LLVMRegister *>(cond) });
-    m_instructions.push_back(ins);
+    m_instructionList.push_back(ins);
 }
 
 void LLVMCodeBuilder::beginElseBranch()
 {
-    m_instructions.push_back(std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, currentLoopScope(), m_loopCondition));
+    m_instructionList.push_back(std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, currentLoopScope(), m_loopCondition));
 }
 
 void LLVMCodeBuilder::endIf()
 {
-    m_instructions.push_back(std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, currentLoopScope(), m_loopCondition));
+    m_instructionList.push_back(std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, currentLoopScope(), m_loopCondition));
 }
 
 void LLVMCodeBuilder::beginRepeatLoop(CompilerValue *count)
@@ -1837,7 +1837,7 @@ void LLVMCodeBuilder::beginRepeatLoop(CompilerValue *count)
 
     auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, currentLoopScope(), m_loopCondition);
     ins->args.push_back({ Compiler::StaticType::Number, dynamic_cast<LLVMRegister *>(count) });
-    m_instructions.push_back(ins);
+    m_instructionList.push_back(ins);
     pushLoopScope(false);
 }
 
@@ -1848,7 +1848,7 @@ void LLVMCodeBuilder::beginWhileLoop(CompilerValue *cond)
 
     auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginWhileLoop, currentLoopScope(), m_loopCondition);
     ins->args.push_back({ Compiler::StaticType::Bool, dynamic_cast<LLVMRegister *>(cond) });
-    m_instructions.push_back(ins);
+    m_instructionList.push_back(ins);
     pushLoopScope(false);
 }
 
@@ -1859,29 +1859,29 @@ void LLVMCodeBuilder::beginRepeatUntilLoop(CompilerValue *cond)
 
     auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, currentLoopScope(), m_loopCondition);
     ins->args.push_back({ Compiler::StaticType::Bool, dynamic_cast<LLVMRegister *>(cond) });
-    m_instructions.push_back(ins);
+    m_instructionList.push_back(ins);
     pushLoopScope(false);
 }
 
 void LLVMCodeBuilder::beginLoopCondition()
 {
     assert(!m_loopCondition);
-    m_instructions.push_back(std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginLoopCondition, currentLoopScope(), m_loopCondition));
+    m_instructionList.push_back(std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginLoopCondition, currentLoopScope(), m_loopCondition));
     m_loopCondition = true;
 }
 
 void LLVMCodeBuilder::endLoop()
 {
     if (!m_warp)
-        m_instructions.push_back(std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Yield, currentLoopScope(), m_loopCondition));
+        m_instructionList.push_back(std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Yield, currentLoopScope(), m_loopCondition));
 
-    m_instructions.push_back(std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, currentLoopScope(), m_loopCondition));
+    m_instructionList.push_back(std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, currentLoopScope(), m_loopCondition));
     popLoopScope();
 }
 
 void LLVMCodeBuilder::yield()
 {
-    m_instructions.push_back(std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Yield, currentLoopScope(), m_loopCondition));
+    m_instructionList.push_back(std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Yield, currentLoopScope(), m_loopCondition));
 
     if (m_loopScope >= 0)
         m_loopScopes[m_loopScope]->containsYield = true;
@@ -1889,7 +1889,7 @@ void LLVMCodeBuilder::yield()
 
 void LLVMCodeBuilder::createStop()
 {
-    m_instructions.push_back(std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Stop, currentLoopScope(), m_loopCondition));
+    m_instructionList.push_back(std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Stop, currentLoopScope(), m_loopCondition));
 }
 
 void LLVMCodeBuilder::createProcedureCall(BlockPrototype *prototype, const Compiler::Args &args)
@@ -2551,7 +2551,7 @@ bool LLVMCodeBuilder::isVarOrListTypeSafe(std::shared_ptr<LLVMInstruction> ins,
     else
         log.insert(ins.get());
 
-    assert(std::find(m_instructions.begin(), m_instructions.end(), ins) != m_instructions.end());
+    assert(std::find(m_instructionList.begin(), m_instructionList.end(), ins) != m_instructionList.end());
     const LLVMVariablePtr *varPtr = ins->workVariable ? &m_variablePtrs.at(ins->workVariable) : nullptr;
     const LLVMListPtr *listPtr = ins->workList ? &m_listPtrs.at(ins->workList) : nullptr;
     assert((varPtr || listPtr) && !(varPtr && listPtr));
@@ -2715,7 +2715,7 @@ LLVMRegister *LLVMCodeBuilder::createOp(const LLVMInstruction &ins, Compiler::St
 LLVMRegister *LLVMCodeBuilder::createOp(const LLVMInstruction &ins, Compiler::StaticType retType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args)
 {
     auto createdIns = std::make_shared<LLVMInstruction>(ins);
-    m_instructions.push_back(createdIns);
+    m_instructionList.push_back(createdIns);
 
     for (size_t i = 0; i < args.size(); i++)
         createdIns->args.push_back({ argTypes[i], dynamic_cast<LLVMRegister *>(args[i]) });
diff --git a/src/engine/internal/llvm/llvmcodebuilder.h b/src/engine/internal/llvm/llvmcodebuilder.h
index cc533b68..45f0e7d8 100644
--- a/src/engine/internal/llvm/llvmcodebuilder.h
+++ b/src/engine/internal/llvm/llvmcodebuilder.h
@@ -234,7 +234,7 @@ class LLVMCodeBuilder : public ICodeBuilder
         llvm::StructType *m_stringPtrType = nullptr;
         llvm::FunctionType *m_resumeFuncType = nullptr;
 
-        [[deprecated]] std::vector<std::shared_ptr<LLVMInstruction>> m_instructions; // TODO: Remove this
+        [[deprecated]] std::vector<std::shared_ptr<LLVMInstruction>> m_instructionList; // TODO: Remove this
         std::vector<std::shared_ptr<LLVMRegister>> m_regs;
         std::vector<std::shared_ptr<CompilerLocalVariable>> m_localVars;
         LLVMRegister *m_lastConstValue = nullptr; // for reporters and hat predicates

From 7af866e70feca0d6ee337b0ae9af9166e16d8796 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Tue, 22 Jul 2025 19:35:15 +0200
Subject: [PATCH 05/79] LLVMCodeBuilder: Store instructions in
 LLVMInstructionList

---
 src/engine/internal/llvm/llvmcodebuilder.cpp | 42 ++++++++++++++++----
 src/engine/internal/llvm/llvmcodebuilder.h   |  2 +
 2 files changed, 36 insertions(+), 8 deletions(-)

diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp
index ac8039fc..78483a5c 100644
--- a/src/engine/internal/llvm/llvmcodebuilder.cpp
+++ b/src/engine/internal/llvm/llvmcodebuilder.cpp
@@ -1390,6 +1390,8 @@ CompilerValue *LLVMCodeBuilder::addFunctionCall(const std::string &functionName,
     for (size_t i = 0; i < args.size(); i++)
         ins->args.push_back({ argTypes[i], dynamic_cast<LLVMRegister *>(args[i]) });
 
+    m_instructions.addInstruction(ins);
+
     if (returnType != Compiler::StaticType::Void) {
         auto reg = std::make_shared<LLVMRegister>(returnType);
         reg->isRawValue = true;
@@ -1456,6 +1458,7 @@ CompilerValue *LLVMCodeBuilder::addVariableValue(Variable *variable)
     ret->isRawValue = false;
     ins->functionReturnReg = ret.get();
 
+    m_instructions.addInstruction(ins);
     m_instructionList.push_back(ins);
     m_variableInstructions.push_back(m_instructionList.back());
     return addReg(ret, ins);
@@ -1486,6 +1489,7 @@ CompilerValue *LLVMCodeBuilder::addListItem(List *list, CompilerValue *index)
     ret->isRawValue = false;
     ins->functionReturnReg = ret.get();
 
+    m_instructions.addInstruction(ins);
     m_instructionList.push_back(ins);
     m_listInstructions.push_back(m_instructionList.back());
     return addReg(ret, ins);
@@ -1549,6 +1553,7 @@ CompilerValue *LLVMCodeBuilder::addProcedureArgument(const std::string &name)
     ins->functionReturnReg = ret.get();
     ins->procedureArgIndex = index;
 
+    m_instructions.addInstruction(ins);
     m_instructionList.push_back(ins);
     return addReg(ret, ins);
 }
@@ -1818,17 +1823,22 @@ void LLVMCodeBuilder::beginIfStatement(CompilerValue *cond)
 {
     auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, currentLoopScope(), m_loopCondition);
     ins->args.push_back({ Compiler::StaticType::Bool, dynamic_cast<LLVMRegister *>(cond) });
+    m_instructions.addInstruction(ins);
     m_instructionList.push_back(ins);
 }
 
 void LLVMCodeBuilder::beginElseBranch()
 {
-    m_instructionList.push_back(std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, currentLoopScope(), m_loopCondition));
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, currentLoopScope(), m_loopCondition);
+    m_instructions.addInstruction(ins);
+    m_instructionList.push_back(ins);
 }
 
 void LLVMCodeBuilder::endIf()
 {
-    m_instructionList.push_back(std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, currentLoopScope(), m_loopCondition));
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, currentLoopScope(), m_loopCondition);
+    m_instructions.addInstruction(ins);
+    m_instructionList.push_back(ins);
 }
 
 void LLVMCodeBuilder::beginRepeatLoop(CompilerValue *count)
@@ -1837,6 +1847,7 @@ void LLVMCodeBuilder::beginRepeatLoop(CompilerValue *count)
 
     auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, currentLoopScope(), m_loopCondition);
     ins->args.push_back({ Compiler::StaticType::Number, dynamic_cast<LLVMRegister *>(count) });
+    m_instructions.addInstruction(ins);
     m_instructionList.push_back(ins);
     pushLoopScope(false);
 }
@@ -1848,6 +1859,7 @@ void LLVMCodeBuilder::beginWhileLoop(CompilerValue *cond)
 
     auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginWhileLoop, currentLoopScope(), m_loopCondition);
     ins->args.push_back({ Compiler::StaticType::Bool, dynamic_cast<LLVMRegister *>(cond) });
+    m_instructions.addInstruction(ins);
     m_instructionList.push_back(ins);
     pushLoopScope(false);
 }
@@ -1859,6 +1871,7 @@ void LLVMCodeBuilder::beginRepeatUntilLoop(CompilerValue *cond)
 
     auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, currentLoopScope(), m_loopCondition);
     ins->args.push_back({ Compiler::StaticType::Bool, dynamic_cast<LLVMRegister *>(cond) });
+    m_instructions.addInstruction(ins);
     m_instructionList.push_back(ins);
     pushLoopScope(false);
 }
@@ -1866,22 +1879,32 @@ void LLVMCodeBuilder::beginRepeatUntilLoop(CompilerValue *cond)
 void LLVMCodeBuilder::beginLoopCondition()
 {
     assert(!m_loopCondition);
-    m_instructionList.push_back(std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginLoopCondition, currentLoopScope(), m_loopCondition));
+
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginLoopCondition, currentLoopScope(), m_loopCondition);
+    m_instructions.addInstruction(ins);
+    m_instructionList.push_back(ins);
     m_loopCondition = true;
 }
 
 void LLVMCodeBuilder::endLoop()
 {
-    if (!m_warp)
-        m_instructionList.push_back(std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Yield, currentLoopScope(), m_loopCondition));
+    if (!m_warp) {
+        auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Yield, currentLoopScope(), m_loopCondition);
+        m_instructions.addInstruction(ins);
+        m_instructionList.push_back(ins);
+    }
 
-    m_instructionList.push_back(std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, currentLoopScope(), m_loopCondition));
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, currentLoopScope(), m_loopCondition);
+    m_instructions.addInstruction(ins);
+    m_instructionList.push_back(ins);
     popLoopScope();
 }
 
 void LLVMCodeBuilder::yield()
 {
-    m_instructionList.push_back(std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Yield, currentLoopScope(), m_loopCondition));
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Yield, currentLoopScope(), m_loopCondition);
+    m_instructions.addInstruction(ins);
+    m_instructionList.push_back(ins);
 
     if (m_loopScope >= 0)
         m_loopScopes[m_loopScope]->containsYield = true;
@@ -1889,7 +1912,9 @@ void LLVMCodeBuilder::yield()
 
 void LLVMCodeBuilder::createStop()
 {
-    m_instructionList.push_back(std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Stop, currentLoopScope(), m_loopCondition));
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Stop, currentLoopScope(), m_loopCondition);
+    m_instructions.addInstruction(ins);
+    m_instructionList.push_back(ins);
 }
 
 void LLVMCodeBuilder::createProcedureCall(BlockPrototype *prototype, const Compiler::Args &args)
@@ -2715,6 +2740,7 @@ LLVMRegister *LLVMCodeBuilder::createOp(const LLVMInstruction &ins, Compiler::St
 LLVMRegister *LLVMCodeBuilder::createOp(const LLVMInstruction &ins, Compiler::StaticType retType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args)
 {
     auto createdIns = std::make_shared<LLVMInstruction>(ins);
+    m_instructions.addInstruction(createdIns);
     m_instructionList.push_back(createdIns);
 
     for (size_t i = 0; i < args.size(); i++)
diff --git a/src/engine/internal/llvm/llvmcodebuilder.h b/src/engine/internal/llvm/llvmcodebuilder.h
index 45f0e7d8..fb1b1a03 100644
--- a/src/engine/internal/llvm/llvmcodebuilder.h
+++ b/src/engine/internal/llvm/llvmcodebuilder.h
@@ -11,6 +11,7 @@
 
 #include "../icodebuilder.h"
 #include "llvminstruction.h"
+#include "llvminstructionlist.h"
 #include "llvmcoroutine.h"
 #include "llvmvariableptr.h"
 #include "llvmlistptr.h"
@@ -235,6 +236,7 @@ class LLVMCodeBuilder : public ICodeBuilder
         llvm::FunctionType *m_resumeFuncType = nullptr;
 
         [[deprecated]] std::vector<std::shared_ptr<LLVMInstruction>> m_instructionList; // TODO: Remove this
+        LLVMInstructionList m_instructions;
         std::vector<std::shared_ptr<LLVMRegister>> m_regs;
         std::vector<std::shared_ptr<CompilerLocalVariable>> m_localVars;
         LLVMRegister *m_lastConstValue = nullptr; // for reporters and hat predicates

From b07f1e16315ab9c49f444839a3291e0ae7c1be42 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Tue, 22 Jul 2025 20:22:24 +0200
Subject: [PATCH 06/79] LLVMInstructionList: Add missing const qualifiers

---
 src/engine/internal/llvm/llvminstructionlist.cpp | 4 ++--
 src/engine/internal/llvm/llvminstructionlist.h   | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/engine/internal/llvm/llvminstructionlist.cpp b/src/engine/internal/llvm/llvminstructionlist.cpp
index 1f4fbe6a..240afe12 100644
--- a/src/engine/internal/llvm/llvminstructionlist.cpp
+++ b/src/engine/internal/llvm/llvminstructionlist.cpp
@@ -7,12 +7,12 @@
 
 using namespace libscratchcpp;
 
-LLVMInstruction *LLVMInstructionList::first()
+LLVMInstruction *LLVMInstructionList::first() const
 {
     return m_first.get();
 }
 
-LLVMInstruction *LLVMInstructionList::last()
+LLVMInstruction *LLVMInstructionList::last() const
 {
     return m_last.get();
 }
diff --git a/src/engine/internal/llvm/llvminstructionlist.h b/src/engine/internal/llvm/llvminstructionlist.h
index 82036555..e47f4304 100644
--- a/src/engine/internal/llvm/llvminstructionlist.h
+++ b/src/engine/internal/llvm/llvminstructionlist.h
@@ -15,8 +15,8 @@ class LLVMInstructionList
         LLVMInstructionList() = default;
         LLVMInstructionList(const LLVMInstructionList &) = delete;
 
-        LLVMInstruction *first();
-        LLVMInstruction *last();
+        LLVMInstruction *first() const;
+        LLVMInstruction *last() const;
 
         void addInstruction(std::shared_ptr<LLVMInstruction> ins);
 

From 2edff3b16f927a2efdbba3cf52e2369955876326 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Tue, 22 Jul 2025 20:39:39 +0200
Subject: [PATCH 07/79] LLVMInstructionList: Add containsInstruction() method

---
 .../internal/llvm/llvminstructionlist.cpp     | 14 +++
 .../internal/llvm/llvminstructionlist.h       |  1 +
 test/llvm/llvminstructionlist_test.cpp        | 93 +++++++++++++++++++
 3 files changed, 108 insertions(+)

diff --git a/src/engine/internal/llvm/llvminstructionlist.cpp b/src/engine/internal/llvm/llvminstructionlist.cpp
index 240afe12..75162af8 100644
--- a/src/engine/internal/llvm/llvminstructionlist.cpp
+++ b/src/engine/internal/llvm/llvminstructionlist.cpp
@@ -17,6 +17,20 @@ LLVMInstruction *LLVMInstructionList::last() const
     return m_last.get();
 }
 
+bool LLVMInstructionList::containsInstruction(LLVMInstruction *ins) const
+{
+    LLVMInstruction *ptr = m_first.get();
+
+    while (ptr) {
+        if (ptr == ins)
+            return true;
+
+        ptr = ptr->next;
+    }
+
+    return false;
+}
+
 void LLVMInstructionList::addInstruction(std::shared_ptr<LLVMInstruction> ins)
 {
     if (!(m_first && m_last)) {
diff --git a/src/engine/internal/llvm/llvminstructionlist.h b/src/engine/internal/llvm/llvminstructionlist.h
index e47f4304..9502ce1b 100644
--- a/src/engine/internal/llvm/llvminstructionlist.h
+++ b/src/engine/internal/llvm/llvminstructionlist.h
@@ -18,6 +18,7 @@ class LLVMInstructionList
         LLVMInstruction *first() const;
         LLVMInstruction *last() const;
 
+        bool containsInstruction(LLVMInstruction *ins) const;
         void addInstruction(std::shared_ptr<LLVMInstruction> ins);
 
     private:
diff --git a/test/llvm/llvminstructionlist_test.cpp b/test/llvm/llvminstructionlist_test.cpp
index ec585179..6ba920f5 100644
--- a/test/llvm/llvminstructionlist_test.cpp
+++ b/test/llvm/llvminstructionlist_test.cpp
@@ -17,6 +17,99 @@ TEST(LLVMInstructionListTest, EmptyList_Last)
     ASSERT_EQ(list.last(), nullptr);
 }
 
+TEST(LLVMInstructionListTest, EmptyList_ContainsNull)
+{
+    LLVMInstructionList list;
+    ASSERT_FALSE(list.containsInstruction(nullptr));
+}
+
+TEST(LLVMInstructionListTest, EmptyList_Contains)
+{
+    LLVMInstructionList list;
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    ASSERT_FALSE(list.containsInstruction(ins.get()));
+}
+
+TEST(LLVMInstructionListTest, SingleInstructionList_ContainsExistent)
+{
+    LLVMInstructionList list;
+
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins1);
+
+    ASSERT_TRUE(list.containsInstruction(ins1.get()));
+}
+
+TEST(LLVMInstructionListTest, SingleInstructionList_ContainsNonExistent)
+{
+    LLVMInstructionList list;
+
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins1);
+
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    ASSERT_FALSE(list.containsInstruction(ins.get()));
+}
+
+TEST(LLVMInstructionListTest, SingleInstructionList_ContainsNull)
+{
+    LLVMInstructionList list;
+
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins1);
+
+    ASSERT_FALSE(list.containsInstruction(nullptr));
+}
+
+TEST(LLVMInstructionListTest, MultipleInstructionList_ContainsExistent)
+{
+    LLVMInstructionList list;
+
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins1);
+
+    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins2);
+
+    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins3);
+
+    ASSERT_TRUE(list.containsInstruction(ins2.get()));
+}
+
+TEST(LLVMInstructionListTest, MultipleInstructionList_ContainsNonExistent)
+{
+    LLVMInstructionList list;
+
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins1);
+
+    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins2);
+
+    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins3);
+
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    ASSERT_FALSE(list.containsInstruction(ins.get()));
+}
+
+TEST(LLVMInstructionListTest, MultipleInstructionList_ContainsNull)
+{
+    LLVMInstructionList list;
+
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins1);
+
+    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins2);
+
+    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins3);
+
+    ASSERT_FALSE(list.containsInstruction(nullptr));
+}
+
 TEST(LLVMInstructionListTest, AddSingleInstruction_First)
 {
     LLVMInstructionList list;

From 7db5a2a0d306f370164f850923cf895fff73e20a Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Tue, 22 Jul 2025 20:40:37 +0200
Subject: [PATCH 08/79] LLVMCodeBuilder: Use raw pointers for variable and list
 instructions

---
 src/engine/internal/llvm/llvmcodebuilder.cpp | 57 ++++++++++----------
 src/engine/internal/llvm/llvmcodebuilder.h   | 10 ++--
 2 files changed, 33 insertions(+), 34 deletions(-)

diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp
index 78483a5c..9fd9913e 100644
--- a/src/engine/internal/llvm/llvmcodebuilder.cpp
+++ b/src/engine/internal/llvm/llvmcodebuilder.cpp
@@ -121,7 +121,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
         // If there are no write operations outside loops, initialize the stack variable now
         Variable *variable = var;
-        auto it = std::find_if(m_variableInstructions.begin(), m_variableInstructions.end(), [variable](const std::shared_ptr<LLVMInstruction> &ins) {
+        auto it = std::find_if(m_variableInstructions.begin(), m_variableInstructions.end(), [variable](const LLVMInstruction *ins) {
             return ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == variable && !ins->loopScope;
         });
 
@@ -743,7 +743,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 LLVMVariablePtr &varPtr = m_variablePtrs[step.workVariable];
                 varPtr.changed = true;
 
-                const bool safe = isVarOrListTypeSafe(insPtr, varPtr.type);
+                const bool safe = isVarOrListTypeSafe(insPtr.get(), varPtr.type);
 
                 // Initialize stack variable on first assignment
                 if (!varPtr.onStack) {
@@ -778,7 +778,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 assert(step.args.size() == 0);
                 LLVMVariablePtr &varPtr = m_variablePtrs[step.workVariable];
 
-                if (!isVarOrListTypeSafe(insPtr, varPtr.type))
+                if (!isVarOrListTypeSafe(insPtr.get(), varPtr.type))
                     varPtr.type = Compiler::StaticType::Unknown;
 
                 step.functionReturnReg->value = varPtr.onStack && !(step.loopCondition && !m_warp) ? varPtr.stackPtr : varPtr.heapPtr;
@@ -806,7 +806,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 const auto &arg = step.args[0];
                 LLVMListPtr &listPtr = m_listPtrs[step.workList];
 
-                if (!isVarOrListTypeSafe(insPtr, listPtr.type))
+                if (!isVarOrListTypeSafe(insPtr.get(), listPtr.type))
                     listPtr.type = Compiler::StaticType::Unknown;
 
                 // Range check
@@ -846,7 +846,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                     typeMap[&listPtr] = listPtr.type;
                 }
 
-                if (!isVarOrListTypeSafe(insPtr, listPtr.type))
+                if (!isVarOrListTypeSafe(insPtr.get(), listPtr.type))
                     listPtr.type = Compiler::StaticType::Unknown;
 
                 // Check if enough space is allocated
@@ -894,7 +894,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                     typeMap[&listPtr] = listPtr.type;
                 }
 
-                if (!isVarOrListTypeSafe(insPtr, listPtr.type))
+                if (!isVarOrListTypeSafe(insPtr.get(), listPtr.type))
                     listPtr.type = Compiler::StaticType::Unknown;
 
                 llvm::Value *oldAllocatedSize = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.allocatedSizePtr);
@@ -933,7 +933,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 Compiler::StaticType type = optimizeRegisterType(valueArg.second);
                 LLVMListPtr &listPtr = m_listPtrs[step.workList];
 
-                if (!isVarOrListTypeSafe(insPtr, listPtr.type))
+                if (!isVarOrListTypeSafe(insPtr.get(), listPtr.type))
                     listPtr.type = Compiler::StaticType::Unknown;
 
                 // Range check
@@ -981,7 +981,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 const auto &arg = step.args[0];
                 LLVMListPtr &listPtr = m_listPtrs[step.workList];
 
-                if (!isVarOrListTypeSafe(insPtr, listPtr.type))
+                if (!isVarOrListTypeSafe(insPtr.get(), listPtr.type))
                     listPtr.type = Compiler::StaticType::Unknown;
 
                 llvm::Value *min = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0));
@@ -1012,7 +1012,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 const auto &arg = step.args[0];
                 LLVMListPtr &listPtr = m_listPtrs[step.workList];
 
-                if (!isVarOrListTypeSafe(insPtr, listPtr.type))
+                if (!isVarOrListTypeSafe(insPtr.get(), listPtr.type))
                     listPtr.type = Compiler::StaticType::Unknown;
 
                 step.functionReturnReg->value = m_builder.CreateSIToFP(getListItemIndex(listPtr, arg.second), m_builder.getDoubleTy());
@@ -1024,7 +1024,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 const auto &arg = step.args[0];
                 LLVMListPtr &listPtr = m_listPtrs[step.workList];
 
-                if (!isVarOrListTypeSafe(insPtr, listPtr.type))
+                if (!isVarOrListTypeSafe(insPtr.get(), listPtr.type))
                     listPtr.type = Compiler::StaticType::Unknown;
 
                 llvm::Value *index = getListItemIndex(listPtr, arg.second);
@@ -1460,7 +1460,7 @@ CompilerValue *LLVMCodeBuilder::addVariableValue(Variable *variable)
 
     m_instructions.addInstruction(ins);
     m_instructionList.push_back(ins);
-    m_variableInstructions.push_back(m_instructionList.back());
+    m_variableInstructions.push_back(ins.get());
     return addReg(ret, ins);
 }
 
@@ -1491,7 +1491,7 @@ CompilerValue *LLVMCodeBuilder::addListItem(List *list, CompilerValue *index)
 
     m_instructions.addInstruction(ins);
     m_instructionList.push_back(ins);
-    m_listInstructions.push_back(m_instructionList.back());
+    m_listInstructions.push_back(ins.get());
     return addReg(ret, ins);
 }
 
@@ -1504,7 +1504,7 @@ CompilerValue *LLVMCodeBuilder::addListItemIndex(List *list, CompilerValue *item
         m_listPtrs[list] = LLVMListPtr();
 
     auto ret = createOp(ins, Compiler::StaticType::Number, Compiler::StaticType::Unknown, { item });
-    m_listInstructions.push_back(m_instructionList.back());
+    m_listInstructions.push_back(m_instructions.last());
     return ret;
 }
 
@@ -1517,7 +1517,7 @@ CompilerValue *LLVMCodeBuilder::addListContains(List *list, CompilerValue *item)
         m_listPtrs[list] = LLVMListPtr();
 
     auto ret = createOp(ins, Compiler::StaticType::Bool, Compiler::StaticType::Unknown, { item });
-    m_listInstructions.push_back(m_instructionList.back());
+    m_listInstructions.push_back(m_instructions.last());
     return ret;
 }
 
@@ -1745,7 +1745,7 @@ void LLVMCodeBuilder::createVariableWrite(Variable *variable, CompilerValue *val
         m_variablePtrs[variable].loopVariableWrites[scope.get()].push_back(m_instructionList.back());
     }
 
-    m_variableInstructions.push_back(m_instructionList.back());
+    m_variableInstructions.push_back(m_instructions.last());
 }
 
 void LLVMCodeBuilder::createListClear(List *list)
@@ -1782,7 +1782,7 @@ void LLVMCodeBuilder::createListAppend(List *list, CompilerValue *item)
         m_listPtrs[list].loopListWrites[scope.get()].push_back(m_instructionList.back());
     }
 
-    m_listInstructions.push_back(m_instructionList.back());
+    m_listInstructions.push_back(m_instructions.last());
 }
 
 void LLVMCodeBuilder::createListInsert(List *list, CompilerValue *index, CompilerValue *item)
@@ -1799,7 +1799,7 @@ void LLVMCodeBuilder::createListInsert(List *list, CompilerValue *index, Compile
         m_listPtrs[list].loopListWrites[scope.get()].push_back(m_instructionList.back());
     }
 
-    m_listInstructions.push_back(m_instructionList.back());
+    m_listInstructions.push_back(m_instructions.last());
 }
 
 void LLVMCodeBuilder::createListReplace(List *list, CompilerValue *index, CompilerValue *item)
@@ -1816,7 +1816,7 @@ void LLVMCodeBuilder::createListReplace(List *list, CompilerValue *index, Compil
         m_listPtrs[list].loopListWrites[scope.get()].push_back(m_instructionList.back());
     }
 
-    m_listInstructions.push_back(m_instructionList.back());
+    m_listInstructions.push_back(m_instructions.last());
 }
 
 void LLVMCodeBuilder::beginIfStatement(CompilerValue *cond)
@@ -2528,14 +2528,14 @@ void LLVMCodeBuilder::updateListDataPtr(const LLVMListPtr &listPtr)
     m_builder.CreateStore(m_builder.getInt1(false), listPtr.dataPtrDirty);
 }
 
-bool LLVMCodeBuilder::isVarOrListTypeSafe(std::shared_ptr<LLVMInstruction> ins, Compiler::StaticType expectedType) const
+bool LLVMCodeBuilder::isVarOrListTypeSafe(LLVMInstruction *ins, Compiler::StaticType expectedType) const
 {
     std::unordered_set<LLVMInstruction *> processed;
     int counter = 0;
     return isVarOrListTypeSafe(ins, expectedType, processed, counter);
 }
 
-bool LLVMCodeBuilder::isVarOrListTypeSafe(std::shared_ptr<LLVMInstruction> ins, Compiler::StaticType expectedType, std::unordered_set<LLVMInstruction *> &log, int &c) const
+bool LLVMCodeBuilder::isVarOrListTypeSafe(LLVMInstruction *ins, Compiler::StaticType expectedType, std::unordered_set<LLVMInstruction *> &log, int &c) const
 {
     /*
      * The main part of the loop type analyzer.
@@ -2571,12 +2571,12 @@ bool LLVMCodeBuilder::isVarOrListTypeSafe(std::shared_ptr<LLVMInstruction> ins,
      *
      * Increment counter to ignore last n write operations.
      */
-    if (log.find(ins.get()) != log.cend())
+    if (log.find(ins) != log.cend())
         c++;
     else
-        log.insert(ins.get());
+        log.insert(ins);
 
-    assert(std::find(m_instructionList.begin(), m_instructionList.end(), ins) != m_instructionList.end());
+    assert(m_instructions.containsInstruction(ins));
     const LLVMVariablePtr *varPtr = ins->workVariable ? &m_variablePtrs.at(ins->workVariable) : nullptr;
     const LLVMListPtr *listPtr = ins->workList ? &m_listPtrs.at(ins->workList) : nullptr;
     assert((varPtr || listPtr) && !(varPtr && listPtr));
@@ -2590,7 +2590,7 @@ bool LLVMCodeBuilder::isVarOrListTypeSafe(std::shared_ptr<LLVMInstruction> ins,
     if (scope->containsYield && !m_warp)
         return false;
 
-    std::shared_ptr<LLVMInstruction> write;
+    LLVMInstruction *write = nullptr;
     const auto &instructions = varPtr ? m_variableInstructions : m_listInstructions;
 
     // Find this instruction
@@ -2646,7 +2646,7 @@ bool LLVMCodeBuilder::isVarOrListTypeSafe(std::shared_ptr<LLVMInstruction> ins,
     }
 
     // Get all write operations in all loop scopes (from the root loop scope)
-    std::vector<std::shared_ptr<LLVMInstruction>> lastWrites;
+    std::vector<LLVMInstruction *> lastWrites;
 
     while (checkScope) {
         auto it = loopWrites.find(checkScope);
@@ -2656,7 +2656,7 @@ bool LLVMCodeBuilder::isVarOrListTypeSafe(std::shared_ptr<LLVMInstruction> ins,
             const auto &writes = it->second;
 
             for (auto w : writes)
-                lastWrites.push_back(w);
+                lastWrites.push_back(w.get());
         }
 
         if (checkScope->childScopes.empty())
@@ -2693,8 +2693,7 @@ bool LLVMCodeBuilder::isVarOrListTypeSafe(std::shared_ptr<LLVMInstruction> ins,
         return false;
 }
 
-bool LLVMCodeBuilder::isVarOrListWriteResultTypeSafe(std::shared_ptr<LLVMInstruction> ins, Compiler::StaticType expectedType, bool ignoreSavedType, std::unordered_set<LLVMInstruction *> &log, int &c)
-    const
+bool LLVMCodeBuilder::isVarOrListWriteResultTypeSafe(LLVMInstruction *ins, Compiler::StaticType expectedType, bool ignoreSavedType, std::unordered_set<LLVMInstruction *> &log, int &c) const
 {
     const LLVMVariablePtr *varPtr = ins->workVariable ? &m_variablePtrs.at(ins->workVariable) : nullptr;
     const LLVMListPtr *listPtr = ins->workList ? &m_listPtrs.at(ins->workList) : nullptr;
@@ -2705,7 +2704,7 @@ bool LLVMCodeBuilder::isVarOrListWriteResultTypeSafe(std::shared_ptr<LLVMInstruc
     auto argIns = arg->instruction;
 
     if (argIns && (argIns->type == LLVMInstruction::Type::ReadVariable || argIns->type == LLVMInstruction::Type::GetListItem))
-        return isVarOrListTypeSafe(argIns, expectedType, log, c);
+        return isVarOrListTypeSafe(argIns.get(), expectedType, log, c);
 
     // Check written type
     const bool typeMatches = (optimizeRegisterType(arg) == expectedType);
diff --git a/src/engine/internal/llvm/llvmcodebuilder.h b/src/engine/internal/llvm/llvmcodebuilder.h
index fb1b1a03..cef8c9f4 100644
--- a/src/engine/internal/llvm/llvmcodebuilder.h
+++ b/src/engine/internal/llvm/llvmcodebuilder.h
@@ -154,9 +154,9 @@ class LLVMCodeBuilder : public ICodeBuilder
         void reloadVariables(llvm::Value *targetVariables);
         void reloadLists();
         void updateListDataPtr(const LLVMListPtr &listPtr);
-        bool isVarOrListTypeSafe(std::shared_ptr<LLVMInstruction> ins, Compiler::StaticType expectedType) const;
-        bool isVarOrListTypeSafe(std::shared_ptr<LLVMInstruction> ins, Compiler::StaticType expectedType, std::unordered_set<LLVMInstruction *> &log, int &c) const;
-        bool isVarOrListWriteResultTypeSafe(std::shared_ptr<LLVMInstruction> ins, Compiler::StaticType expectedType, bool ignoreSavedType, std::unordered_set<LLVMInstruction *> &log, int &c) const;
+        bool isVarOrListTypeSafe(LLVMInstruction *ins, Compiler::StaticType expectedType) const;
+        bool isVarOrListTypeSafe(LLVMInstruction *ins, Compiler::StaticType expectedType, std::unordered_set<LLVMInstruction *> &log, int &c) const;
+        bool isVarOrListWriteResultTypeSafe(LLVMInstruction *ins, Compiler::StaticType expectedType, bool ignoreSavedType, std::unordered_set<LLVMInstruction *> &log, int &c) const;
 
         LLVMRegister *createOp(LLVMInstruction::Type type, Compiler::StaticType retType, Compiler::StaticType argType, const Compiler::Args &args);
         LLVMRegister *createOp(LLVMInstruction::Type type, Compiler::StaticType retType, const Compiler::ArgTypes &argTypes = {}, const Compiler::Args &args = {});
@@ -251,8 +251,8 @@ class LLVMCodeBuilder : public ICodeBuilder
         long m_loopScopeCounter = 0; // replacement for m_loopScopes size in build phase
         std::vector<long> m_loopScopeTree;
         bool m_loopCondition = false; // whether we're currently compiling a loop condition
-        std::vector<std::shared_ptr<LLVMInstruction>> m_variableInstructions;
-        std::vector<std::shared_ptr<LLVMInstruction>> m_listInstructions;
+        std::vector<LLVMInstruction *> m_variableInstructions;
+        std::vector<LLVMInstruction *> m_listInstructions;
         std::vector<std::vector<llvm::Value *>> m_stringHeap; // scopes
 
         std::shared_ptr<ExecutableCode> m_output;

From b00c6da57815ba8d1eac69df5010a62489793395 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Tue, 22 Jul 2025 20:51:10 +0200
Subject: [PATCH 09/79] LLVMCodeBuilder: Read instructions from m_instructions

---
 src/engine/internal/llvm/llvmcodebuilder.cpp | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp
index 9fd9913e..51919450 100644
--- a/src/engine/internal/llvm/llvmcodebuilder.cpp
+++ b/src/engine/internal/llvm/llvmcodebuilder.cpp
@@ -153,7 +153,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
     pushScopeLevel();
 
     // Execute recorded steps
-    for (const auto insPtr : m_instructionList) {
+    for (LLVMInstruction *insPtr = m_instructions.first(); insPtr; insPtr = insPtr->next) {
         const LLVMInstruction &step = *insPtr;
 
         switch (step.type) {
@@ -743,7 +743,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 LLVMVariablePtr &varPtr = m_variablePtrs[step.workVariable];
                 varPtr.changed = true;
 
-                const bool safe = isVarOrListTypeSafe(insPtr.get(), varPtr.type);
+                const bool safe = isVarOrListTypeSafe(insPtr, varPtr.type);
 
                 // Initialize stack variable on first assignment
                 if (!varPtr.onStack) {
@@ -778,7 +778,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 assert(step.args.size() == 0);
                 LLVMVariablePtr &varPtr = m_variablePtrs[step.workVariable];
 
-                if (!isVarOrListTypeSafe(insPtr.get(), varPtr.type))
+                if (!isVarOrListTypeSafe(insPtr, varPtr.type))
                     varPtr.type = Compiler::StaticType::Unknown;
 
                 step.functionReturnReg->value = varPtr.onStack && !(step.loopCondition && !m_warp) ? varPtr.stackPtr : varPtr.heapPtr;
@@ -806,7 +806,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 const auto &arg = step.args[0];
                 LLVMListPtr &listPtr = m_listPtrs[step.workList];
 
-                if (!isVarOrListTypeSafe(insPtr.get(), listPtr.type))
+                if (!isVarOrListTypeSafe(insPtr, listPtr.type))
                     listPtr.type = Compiler::StaticType::Unknown;
 
                 // Range check
@@ -846,7 +846,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                     typeMap[&listPtr] = listPtr.type;
                 }
 
-                if (!isVarOrListTypeSafe(insPtr.get(), listPtr.type))
+                if (!isVarOrListTypeSafe(insPtr, listPtr.type))
                     listPtr.type = Compiler::StaticType::Unknown;
 
                 // Check if enough space is allocated
@@ -894,7 +894,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                     typeMap[&listPtr] = listPtr.type;
                 }
 
-                if (!isVarOrListTypeSafe(insPtr.get(), listPtr.type))
+                if (!isVarOrListTypeSafe(insPtr, listPtr.type))
                     listPtr.type = Compiler::StaticType::Unknown;
 
                 llvm::Value *oldAllocatedSize = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.allocatedSizePtr);
@@ -933,7 +933,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 Compiler::StaticType type = optimizeRegisterType(valueArg.second);
                 LLVMListPtr &listPtr = m_listPtrs[step.workList];
 
-                if (!isVarOrListTypeSafe(insPtr.get(), listPtr.type))
+                if (!isVarOrListTypeSafe(insPtr, listPtr.type))
                     listPtr.type = Compiler::StaticType::Unknown;
 
                 // Range check
@@ -981,7 +981,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 const auto &arg = step.args[0];
                 LLVMListPtr &listPtr = m_listPtrs[step.workList];
 
-                if (!isVarOrListTypeSafe(insPtr.get(), listPtr.type))
+                if (!isVarOrListTypeSafe(insPtr, listPtr.type))
                     listPtr.type = Compiler::StaticType::Unknown;
 
                 llvm::Value *min = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0));
@@ -1012,7 +1012,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 const auto &arg = step.args[0];
                 LLVMListPtr &listPtr = m_listPtrs[step.workList];
 
-                if (!isVarOrListTypeSafe(insPtr.get(), listPtr.type))
+                if (!isVarOrListTypeSafe(insPtr, listPtr.type))
                     listPtr.type = Compiler::StaticType::Unknown;
 
                 step.functionReturnReg->value = m_builder.CreateSIToFP(getListItemIndex(listPtr, arg.second), m_builder.getDoubleTy());
@@ -1024,7 +1024,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 const auto &arg = step.args[0];
                 LLVMListPtr &listPtr = m_listPtrs[step.workList];
 
-                if (!isVarOrListTypeSafe(insPtr.get(), listPtr.type))
+                if (!isVarOrListTypeSafe(insPtr, listPtr.type))
                     listPtr.type = Compiler::StaticType::Unknown;
 
                 llvm::Value *index = getListItemIndex(listPtr, arg.second);

From b0b8c7e238130bfd39277474da4c406e8734f2f9 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Tue, 22 Jul 2025 21:05:02 +0200
Subject: [PATCH 10/79] LLVMInstructionList: Add predicate-based contains
 method

---
 .../internal/llvm/llvminstructionlist.cpp     | 14 +++++
 .../internal/llvm/llvminstructionlist.h       |  3 +
 test/llvm/llvminstructionlist_test.cpp        | 60 +++++++++++++++++++
 3 files changed, 77 insertions(+)

diff --git a/src/engine/internal/llvm/llvminstructionlist.cpp b/src/engine/internal/llvm/llvminstructionlist.cpp
index 75162af8..f8ad62ef 100644
--- a/src/engine/internal/llvm/llvminstructionlist.cpp
+++ b/src/engine/internal/llvm/llvminstructionlist.cpp
@@ -31,6 +31,20 @@ bool LLVMInstructionList::containsInstruction(LLVMInstruction *ins) const
     return false;
 }
 
+bool LLVMInstructionList::containsInstruction(std::function<bool(const LLVMInstruction *)> func) const
+{
+    LLVMInstruction *ptr = m_first.get();
+
+    while (ptr) {
+        if (func(ptr))
+            return true;
+
+        ptr = ptr->next;
+    }
+
+    return false;
+}
+
 void LLVMInstructionList::addInstruction(std::shared_ptr<LLVMInstruction> ins)
 {
     if (!(m_first && m_last)) {
diff --git a/src/engine/internal/llvm/llvminstructionlist.h b/src/engine/internal/llvm/llvminstructionlist.h
index 9502ce1b..54dd4b7f 100644
--- a/src/engine/internal/llvm/llvminstructionlist.h
+++ b/src/engine/internal/llvm/llvminstructionlist.h
@@ -3,6 +3,7 @@
 #pragma once
 
 #include <memory>
+#include <functional>
 
 namespace libscratchcpp
 {
@@ -19,6 +20,8 @@ class LLVMInstructionList
         LLVMInstruction *last() const;
 
         bool containsInstruction(LLVMInstruction *ins) const;
+        bool containsInstruction(std::function<bool(const LLVMInstruction *)> func) const;
+
         void addInstruction(std::shared_ptr<LLVMInstruction> ins);
 
     private:
diff --git a/test/llvm/llvminstructionlist_test.cpp b/test/llvm/llvminstructionlist_test.cpp
index 6ba920f5..902b008b 100644
--- a/test/llvm/llvminstructionlist_test.cpp
+++ b/test/llvm/llvminstructionlist_test.cpp
@@ -23,6 +23,13 @@ TEST(LLVMInstructionListTest, EmptyList_ContainsNull)
     ASSERT_FALSE(list.containsInstruction(nullptr));
 }
 
+TEST(LLVMInstructionListTest, EmptyList_ContainsFunc)
+{
+    LLVMInstructionList list;
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    ASSERT_FALSE(list.containsInstruction([](const LLVMInstruction *) { return true; }));
+}
+
 TEST(LLVMInstructionListTest, EmptyList_Contains)
 {
     LLVMInstructionList list;
@@ -61,6 +68,27 @@ TEST(LLVMInstructionListTest, SingleInstructionList_ContainsNull)
     ASSERT_FALSE(list.containsInstruction(nullptr));
 }
 
+TEST(LLVMInstructionListTest, SingleInstructionList_ContainsFuncTrue)
+{
+    LLVMInstructionList list;
+
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins1);
+
+    ASSERT_TRUE(list.containsInstruction([](const LLVMInstruction *) { return true; }));
+}
+
+TEST(LLVMInstructionListTest, SingleInstructionList_ContainsFuncFalse)
+{
+    LLVMInstructionList list;
+
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins1);
+
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    ASSERT_FALSE(list.containsInstruction([](const LLVMInstruction *) { return false; }));
+}
+
 TEST(LLVMInstructionListTest, MultipleInstructionList_ContainsExistent)
 {
     LLVMInstructionList list;
@@ -110,6 +138,38 @@ TEST(LLVMInstructionListTest, MultipleInstructionList_ContainsNull)
     ASSERT_FALSE(list.containsInstruction(nullptr));
 }
 
+TEST(LLVMInstructionListTest, MultipleInstructionList_ContainsExistentFunc)
+{
+    LLVMInstructionList list;
+
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins1);
+
+    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Stop, nullptr, false);
+    list.addInstruction(ins2);
+
+    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins3);
+
+    ASSERT_TRUE(list.containsInstruction([](const LLVMInstruction *ins) { return ins->type == LLVMInstruction::Type::Stop; }));
+}
+
+TEST(LLVMInstructionListTest, MultipleInstructionList_ContainsNonExistentFunc)
+{
+    LLVMInstructionList list;
+
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins1);
+
+    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins2);
+
+    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins3);
+
+    ASSERT_FALSE(list.containsInstruction([](const LLVMInstruction *ins) { return ins->type == LLVMInstruction::Type::Stop; }));
+}
+
 TEST(LLVMInstructionListTest, AddSingleInstruction_First)
 {
     LLVMInstructionList list;

From 207b328019fe494060a751729b6f370884c99391 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Tue, 22 Jul 2025 21:11:11 +0200
Subject: [PATCH 11/79] LLVMInstructionList: Add empty() method

---
 .../internal/llvm/llvminstructionlist.h       |  2 ++
 test/llvm/llvminstructionlist_test.cpp        | 31 +++++++++++++++++++
 2 files changed, 33 insertions(+)

diff --git a/src/engine/internal/llvm/llvminstructionlist.h b/src/engine/internal/llvm/llvminstructionlist.h
index 54dd4b7f..e7cadb9c 100644
--- a/src/engine/internal/llvm/llvminstructionlist.h
+++ b/src/engine/internal/llvm/llvminstructionlist.h
@@ -19,6 +19,8 @@ class LLVMInstructionList
         LLVMInstruction *first() const;
         LLVMInstruction *last() const;
 
+        bool empty() const { return !first(); }
+
         bool containsInstruction(LLVMInstruction *ins) const;
         bool containsInstruction(std::function<bool(const LLVMInstruction *)> func) const;
 
diff --git a/test/llvm/llvminstructionlist_test.cpp b/test/llvm/llvminstructionlist_test.cpp
index 902b008b..7cc12584 100644
--- a/test/llvm/llvminstructionlist_test.cpp
+++ b/test/llvm/llvminstructionlist_test.cpp
@@ -17,6 +17,12 @@ TEST(LLVMInstructionListTest, EmptyList_Last)
     ASSERT_EQ(list.last(), nullptr);
 }
 
+TEST(LLVMInstructionListTest, EmptyList_Empty)
+{
+    LLVMInstructionList list;
+    ASSERT_TRUE(list.empty());
+}
+
 TEST(LLVMInstructionListTest, EmptyList_ContainsNull)
 {
     LLVMInstructionList list;
@@ -188,6 +194,15 @@ TEST(LLVMInstructionListTest, AddSingleInstruction_Last)
     ASSERT_EQ(list.last(), ins.get());
 }
 
+TEST(LLVMInstructionListTest, AddSingleInstruction_Empty)
+{
+    LLVMInstructionList list;
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins);
+
+    ASSERT_FALSE(list.empty());
+}
+
 TEST(LLVMInstructionListTest, AddSingleInstruction_Previous)
 {
     LLVMInstructionList list;
@@ -238,6 +253,22 @@ TEST(LLVMInstructionListTest, AddMultipleInstructions_Last)
     ASSERT_EQ(list.last(), ins3.get());
 }
 
+TEST(LLVMInstructionListTest, AddMultipleInstructions_Empty)
+{
+    LLVMInstructionList list;
+
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins1);
+
+    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins2);
+
+    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(ins3);
+
+    ASSERT_FALSE(list.empty());
+}
+
 TEST(LLVMInstructionListTest, AddMultipleInstructions_PreviousOfFirst)
 {
     LLVMInstructionList list;

From 80032ee4b95c999e0a55de79635d454aa26e51f9 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Tue, 22 Jul 2025 21:18:54 +0200
Subject: [PATCH 12/79] Use raw pointers for loop var/list write instructions

---
 src/engine/internal/llvm/llvmcodebuilder.cpp | 10 +++++-----
 src/engine/internal/llvm/llvmlistptr.h       |  2 +-
 src/engine/internal/llvm/llvmvariableptr.h   |  2 +-
 3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp
index 51919450..b64deaf7 100644
--- a/src/engine/internal/llvm/llvmcodebuilder.cpp
+++ b/src/engine/internal/llvm/llvmcodebuilder.cpp
@@ -1742,7 +1742,7 @@ void LLVMCodeBuilder::createVariableWrite(Variable *variable, CompilerValue *val
 
     if (m_loopScope >= 0) {
         auto scope = m_loopScopes[m_loopScope];
-        m_variablePtrs[variable].loopVariableWrites[scope.get()].push_back(m_instructionList.back());
+        m_variablePtrs[variable].loopVariableWrites[scope.get()].push_back(m_instructions.last());
     }
 
     m_variableInstructions.push_back(m_instructions.last());
@@ -1779,7 +1779,7 @@ void LLVMCodeBuilder::createListAppend(List *list, CompilerValue *item)
 
     if (m_loopScope >= 0) {
         auto scope = m_loopScopes[m_loopScope];
-        m_listPtrs[list].loopListWrites[scope.get()].push_back(m_instructionList.back());
+        m_listPtrs[list].loopListWrites[scope.get()].push_back(m_instructions.last());
     }
 
     m_listInstructions.push_back(m_instructions.last());
@@ -1796,7 +1796,7 @@ void LLVMCodeBuilder::createListInsert(List *list, CompilerValue *index, Compile
 
     if (m_loopScope >= 0) {
         auto scope = m_loopScopes[m_loopScope];
-        m_listPtrs[list].loopListWrites[scope.get()].push_back(m_instructionList.back());
+        m_listPtrs[list].loopListWrites[scope.get()].push_back(m_instructions.last());
     }
 
     m_listInstructions.push_back(m_instructions.last());
@@ -1813,7 +1813,7 @@ void LLVMCodeBuilder::createListReplace(List *list, CompilerValue *index, Compil
 
     if (m_loopScope >= 0) {
         auto scope = m_loopScopes[m_loopScope];
-        m_listPtrs[list].loopListWrites[scope.get()].push_back(m_instructionList.back());
+        m_listPtrs[list].loopListWrites[scope.get()].push_back(m_instructions.last());
     }
 
     m_listInstructions.push_back(m_instructions.last());
@@ -2656,7 +2656,7 @@ bool LLVMCodeBuilder::isVarOrListTypeSafe(LLVMInstruction *ins, Compiler::Static
             const auto &writes = it->second;
 
             for (auto w : writes)
-                lastWrites.push_back(w.get());
+                lastWrites.push_back(w);
         }
 
         if (checkScope->childScopes.empty())
diff --git a/src/engine/internal/llvm/llvmlistptr.h b/src/engine/internal/llvm/llvmlistptr.h
index 99fc74a3..2dd75869 100644
--- a/src/engine/internal/llvm/llvmlistptr.h
+++ b/src/engine/internal/llvm/llvmlistptr.h
@@ -28,7 +28,7 @@ struct LLVMListPtr
         Compiler::StaticType type = Compiler::StaticType::Unknown;
 
         // Used in build phase to check the type safety of lists in loops
-        std::unordered_map<LLVMLoopScope *, std::vector<std::shared_ptr<LLVMInstruction>>> loopListWrites; // loop scope, write instructions
+        std::unordered_map<LLVMLoopScope *, std::vector<LLVMInstruction *>> loopListWrites; // loop scope, write instructions
 };
 
 } // namespace libscratchcpp
diff --git a/src/engine/internal/llvm/llvmvariableptr.h b/src/engine/internal/llvm/llvmvariableptr.h
index 88ddcc03..9907a5aa 100644
--- a/src/engine/internal/llvm/llvmvariableptr.h
+++ b/src/engine/internal/llvm/llvmvariableptr.h
@@ -27,7 +27,7 @@ struct LLVMVariablePtr
         bool changed = false;
 
         // Used in build phase to check the type safety of variables in loops
-        std::unordered_map<LLVMLoopScope *, std::vector<std::shared_ptr<LLVMInstruction>>> loopVariableWrites; // loop scope, write instructions
+        std::unordered_map<LLVMLoopScope *, std::vector<LLVMInstruction *>> loopVariableWrites; // loop scope, write instructions
 };
 
 } // namespace libscratchcpp

From 7d80b2022d8bf136aedec2dd20d3f1c698fd3e40 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Tue, 22 Jul 2025 21:20:46 +0200
Subject: [PATCH 13/79] LLVMCodeBuilder: Drop m_instructionList

---
 src/engine/internal/llvm/llvmcodebuilder.cpp | 40 ++++++--------------
 src/engine/internal/llvm/llvmcodebuilder.h   |  1 -
 2 files changed, 11 insertions(+), 30 deletions(-)

diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp
index b64deaf7..b61a477b 100644
--- a/src/engine/internal/llvm/llvmcodebuilder.cpp
+++ b/src/engine/internal/llvm/llvmcodebuilder.cpp
@@ -53,12 +53,11 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 {
     if (!m_warp) {
         // Do not create coroutine if there are no yield instructions nor non-warp procedure calls
-        auto it = std::find_if(m_instructionList.begin(), m_instructionList.end(), [](const std::shared_ptr<LLVMInstruction> &step) {
-            return step->type == LLVMInstruction::Type::Yield || (step->type == LLVMInstruction::Type::CallProcedure && step->procedurePrototype && !step->procedurePrototype->warp());
-        });
-
-        if (it == m_instructionList.end())
+        if (!m_instructions.containsInstruction([](const LLVMInstruction *step) {
+                return step->type == LLVMInstruction::Type::Yield || (step->type == LLVMInstruction::Type::CallProcedure && step->procedurePrototype && !step->procedurePrototype->warp());
+            })) {
             m_warp = true;
+        }
 
         // Only create coroutines in scripts
         if (m_codeType != Compiler::CodeType::Script)
@@ -1340,8 +1339,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
         case Compiler::CodeType::Reporter: {
             // Use last instruction return value (or last constant) and create a ValueData instance
-            assert(!m_instructionList.empty() || m_lastConstValue);
-            LLVMRegister *ret = m_instructionList.empty() ? m_lastConstValue : m_instructionList.back()->functionReturnReg;
+            assert(!m_instructions.empty() || m_lastConstValue);
+            LLVMRegister *ret = m_instructions.empty() ? m_lastConstValue : m_instructions.last()->functionReturnReg;
             llvm::Value *copy = createNewValue(ret);
             m_builder.CreateRet(m_builder.CreateLoad(m_valueDataType, copy));
             break;
@@ -1349,12 +1348,12 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
         case Compiler::CodeType::HatPredicate:
             // Use last instruction return value (or last constant)
-            assert(!m_instructionList.empty() || m_lastConstValue);
+            assert(!m_instructions.empty() || m_lastConstValue);
 
-            if (m_instructionList.empty())
+            if (m_instructions.empty())
                 m_builder.CreateRet(castValue(m_lastConstValue, Compiler::StaticType::Bool));
             else
-                m_builder.CreateRet(castValue(m_instructionList.back()->functionReturnReg, Compiler::StaticType::Bool));
+                m_builder.CreateRet(castValue(m_instructions.last()->functionReturnReg, Compiler::StaticType::Bool));
             break;
     }
 
@@ -1396,25 +1395,23 @@ CompilerValue *LLVMCodeBuilder::addFunctionCall(const std::string &functionName,
         auto reg = std::make_shared<LLVMRegister>(returnType);
         reg->isRawValue = true;
         ins->functionReturnReg = reg.get();
-        m_instructionList.push_back(ins);
         return addReg(reg, ins);
     }
 
-    m_instructionList.push_back(ins);
     return nullptr;
 }
 
 CompilerValue *LLVMCodeBuilder::addTargetFunctionCall(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args)
 {
     CompilerValue *ret = addFunctionCall(functionName, returnType, argTypes, args);
-    m_instructionList.back()->functionTargetArg = true;
+    m_instructions.last()->functionTargetArg = true;
     return ret;
 }
 
 CompilerValue *LLVMCodeBuilder::addFunctionCallWithCtx(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args)
 {
     CompilerValue *ret = addFunctionCall(functionName, returnType, argTypes, args);
-    m_instructionList.back()->functionCtxArg = true;
+    m_instructions.last()->functionCtxArg = true;
     return ret;
 }
 
@@ -1459,7 +1456,6 @@ CompilerValue *LLVMCodeBuilder::addVariableValue(Variable *variable)
     ins->functionReturnReg = ret.get();
 
     m_instructions.addInstruction(ins);
-    m_instructionList.push_back(ins);
     m_variableInstructions.push_back(ins.get());
     return addReg(ret, ins);
 }
@@ -1490,7 +1486,6 @@ CompilerValue *LLVMCodeBuilder::addListItem(List *list, CompilerValue *index)
     ins->functionReturnReg = ret.get();
 
     m_instructions.addInstruction(ins);
-    m_instructionList.push_back(ins);
     m_listInstructions.push_back(ins.get());
     return addReg(ret, ins);
 }
@@ -1554,7 +1549,6 @@ CompilerValue *LLVMCodeBuilder::addProcedureArgument(const std::string &name)
     ins->procedureArgIndex = index;
 
     m_instructions.addInstruction(ins);
-    m_instructionList.push_back(ins);
     return addReg(ret, ins);
 }
 
@@ -1824,21 +1818,18 @@ void LLVMCodeBuilder::beginIfStatement(CompilerValue *cond)
     auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, currentLoopScope(), m_loopCondition);
     ins->args.push_back({ Compiler::StaticType::Bool, dynamic_cast<LLVMRegister *>(cond) });
     m_instructions.addInstruction(ins);
-    m_instructionList.push_back(ins);
 }
 
 void LLVMCodeBuilder::beginElseBranch()
 {
     auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, currentLoopScope(), m_loopCondition);
     m_instructions.addInstruction(ins);
-    m_instructionList.push_back(ins);
 }
 
 void LLVMCodeBuilder::endIf()
 {
     auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, currentLoopScope(), m_loopCondition);
     m_instructions.addInstruction(ins);
-    m_instructionList.push_back(ins);
 }
 
 void LLVMCodeBuilder::beginRepeatLoop(CompilerValue *count)
@@ -1848,7 +1839,6 @@ void LLVMCodeBuilder::beginRepeatLoop(CompilerValue *count)
     auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, currentLoopScope(), m_loopCondition);
     ins->args.push_back({ Compiler::StaticType::Number, dynamic_cast<LLVMRegister *>(count) });
     m_instructions.addInstruction(ins);
-    m_instructionList.push_back(ins);
     pushLoopScope(false);
 }
 
@@ -1860,7 +1850,6 @@ void LLVMCodeBuilder::beginWhileLoop(CompilerValue *cond)
     auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginWhileLoop, currentLoopScope(), m_loopCondition);
     ins->args.push_back({ Compiler::StaticType::Bool, dynamic_cast<LLVMRegister *>(cond) });
     m_instructions.addInstruction(ins);
-    m_instructionList.push_back(ins);
     pushLoopScope(false);
 }
 
@@ -1872,7 +1861,6 @@ void LLVMCodeBuilder::beginRepeatUntilLoop(CompilerValue *cond)
     auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, currentLoopScope(), m_loopCondition);
     ins->args.push_back({ Compiler::StaticType::Bool, dynamic_cast<LLVMRegister *>(cond) });
     m_instructions.addInstruction(ins);
-    m_instructionList.push_back(ins);
     pushLoopScope(false);
 }
 
@@ -1882,7 +1870,6 @@ void LLVMCodeBuilder::beginLoopCondition()
 
     auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginLoopCondition, currentLoopScope(), m_loopCondition);
     m_instructions.addInstruction(ins);
-    m_instructionList.push_back(ins);
     m_loopCondition = true;
 }
 
@@ -1891,12 +1878,10 @@ void LLVMCodeBuilder::endLoop()
     if (!m_warp) {
         auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Yield, currentLoopScope(), m_loopCondition);
         m_instructions.addInstruction(ins);
-        m_instructionList.push_back(ins);
     }
 
     auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, currentLoopScope(), m_loopCondition);
     m_instructions.addInstruction(ins);
-    m_instructionList.push_back(ins);
     popLoopScope();
 }
 
@@ -1904,7 +1889,6 @@ void LLVMCodeBuilder::yield()
 {
     auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Yield, currentLoopScope(), m_loopCondition);
     m_instructions.addInstruction(ins);
-    m_instructionList.push_back(ins);
 
     if (m_loopScope >= 0)
         m_loopScopes[m_loopScope]->containsYield = true;
@@ -1914,7 +1898,6 @@ void LLVMCodeBuilder::createStop()
 {
     auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Stop, currentLoopScope(), m_loopCondition);
     m_instructions.addInstruction(ins);
-    m_instructionList.push_back(ins);
 }
 
 void LLVMCodeBuilder::createProcedureCall(BlockPrototype *prototype, const Compiler::Args &args)
@@ -2740,7 +2723,6 @@ LLVMRegister *LLVMCodeBuilder::createOp(const LLVMInstruction &ins, Compiler::St
 {
     auto createdIns = std::make_shared<LLVMInstruction>(ins);
     m_instructions.addInstruction(createdIns);
-    m_instructionList.push_back(createdIns);
 
     for (size_t i = 0; i < args.size(); i++)
         createdIns->args.push_back({ argTypes[i], dynamic_cast<LLVMRegister *>(args[i]) });
diff --git a/src/engine/internal/llvm/llvmcodebuilder.h b/src/engine/internal/llvm/llvmcodebuilder.h
index cef8c9f4..a3b71b2e 100644
--- a/src/engine/internal/llvm/llvmcodebuilder.h
+++ b/src/engine/internal/llvm/llvmcodebuilder.h
@@ -235,7 +235,6 @@ class LLVMCodeBuilder : public ICodeBuilder
         llvm::StructType *m_stringPtrType = nullptr;
         llvm::FunctionType *m_resumeFuncType = nullptr;
 
-        [[deprecated]] std::vector<std::shared_ptr<LLVMInstruction>> m_instructionList; // TODO: Remove this
         LLVMInstructionList m_instructions;
         std::vector<std::shared_ptr<LLVMRegister>> m_regs;
         std::vector<std::shared_ptr<CompilerLocalVariable>> m_localVars;

From 0a813197bd793a647f28b13f09922bb98c815995 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Tue, 22 Jul 2025 21:32:59 +0200
Subject: [PATCH 14/79] Ensure LLVM instructions are not deleted

---
 src/engine/internal/llvm/llvminstruction.h       | 1 +
 src/engine/internal/llvm/llvminstructionlist.cpp | 2 ++
 2 files changed, 3 insertions(+)

diff --git a/src/engine/internal/llvm/llvminstruction.h b/src/engine/internal/llvm/llvminstruction.h
index 1116b347..091539bb 100644
--- a/src/engine/internal/llvm/llvminstruction.h
+++ b/src/engine/internal/llvm/llvminstruction.h
@@ -104,6 +104,7 @@ struct LLVMInstruction
         // Linked list
         LLVMInstruction *previous = nullptr;
         LLVMInstruction *next = nullptr;
+        std::shared_ptr<LLVMInstruction> _next; // ensure items are not deleted
 };
 
 } // namespace libscratchcpp
diff --git a/src/engine/internal/llvm/llvminstructionlist.cpp b/src/engine/internal/llvm/llvminstructionlist.cpp
index f8ad62ef..61b8d6c3 100644
--- a/src/engine/internal/llvm/llvminstructionlist.cpp
+++ b/src/engine/internal/llvm/llvminstructionlist.cpp
@@ -55,8 +55,10 @@ void LLVMInstructionList::addInstruction(std::shared_ptr<LLVMInstruction> ins)
 
         ins->previous = nullptr;
         ins->next = nullptr;
+        ins->_next = nullptr;
     } else {
         m_last->next = ins.get();
+        m_last->_next = ins;
         ins->previous = m_last.get();
         m_last = ins;
     }

From b419577f4b41c74596f9408cc5440e1ba6f15f5a Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Wed, 23 Jul 2025 13:04:47 +0200
Subject: [PATCH 15/79] LLVMCodeBuilder: Store variable pointer in
 LLVMVariablePtr

---
 src/engine/internal/llvm/llvmcodebuilder.cpp | 8 ++++++--
 src/engine/internal/llvm/llvmvariableptr.h   | 1 +
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp
index b61a477b..f39ad665 100644
--- a/src/engine/internal/llvm/llvmcodebuilder.cpp
+++ b/src/engine/internal/llvm/llvmcodebuilder.cpp
@@ -1448,8 +1448,10 @@ CompilerValue *LLVMCodeBuilder::addVariableValue(Variable *variable)
     auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, currentLoopScope(), m_loopCondition);
     ins->workVariable = variable;
 
-    if (m_variablePtrs.find(variable) == m_variablePtrs.cend())
+    if (m_variablePtrs.find(variable) == m_variablePtrs.cend()) {
         m_variablePtrs[variable] = LLVMVariablePtr();
+        m_variablePtrs[variable].var = variable;
+    }
 
     auto ret = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
     ret->isRawValue = false;
@@ -1731,8 +1733,10 @@ void LLVMCodeBuilder::createVariableWrite(Variable *variable, CompilerValue *val
     ins.workVariable = variable;
     createOp(ins, Compiler::StaticType::Void, Compiler::StaticType::Unknown, { value });
 
-    if (m_variablePtrs.find(variable) == m_variablePtrs.cend())
+    if (m_variablePtrs.find(variable) == m_variablePtrs.cend()) {
         m_variablePtrs[variable] = LLVMVariablePtr();
+        m_variablePtrs[variable].var = variable;
+    }
 
     if (m_loopScope >= 0) {
         auto scope = m_loopScopes[m_loopScope];
diff --git a/src/engine/internal/llvm/llvmvariableptr.h b/src/engine/internal/llvm/llvmvariableptr.h
index 9907a5aa..b6da2a30 100644
--- a/src/engine/internal/llvm/llvmvariableptr.h
+++ b/src/engine/internal/llvm/llvmvariableptr.h
@@ -20,6 +20,7 @@ class LLVMInstruction;
 
 struct LLVMVariablePtr
 {
+        Variable *var = nullptr;
         llvm::Value *stackPtr = nullptr;
         llvm::Value *heapPtr = nullptr;
         Compiler::StaticType type = Compiler::StaticType::Unknown;

From da3803954ca267aa39767e7aee7e879849e43a4a Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Wed, 23 Jul 2025 13:05:40 +0200
Subject: [PATCH 16/79] Implement variableTypeChanges() for basic cases

---
 src/engine/internal/llvm/CMakeLists.txt       |   2 +
 src/engine/internal/llvm/llvmloopanalyzer.cpp |  62 ++
 src/engine/internal/llvm/llvmloopanalyzer.h   |  22 +
 test/llvm/CMakeLists.txt                      |   1 +
 .../variabletypechanges_test.cpp              | 570 ++++++++++++++++++
 5 files changed, 657 insertions(+)
 create mode 100644 src/engine/internal/llvm/llvmloopanalyzer.cpp
 create mode 100644 src/engine/internal/llvm/llvmloopanalyzer.h
 create mode 100644 test/llvm/loop_analyzer/variabletypechanges_test.cpp

diff --git a/src/engine/internal/llvm/CMakeLists.txt b/src/engine/internal/llvm/CMakeLists.txt
index 3fcb3d79..fb0617f4 100644
--- a/src/engine/internal/llvm/CMakeLists.txt
+++ b/src/engine/internal/llvm/CMakeLists.txt
@@ -17,6 +17,8 @@ target_sources(scratchcpp
     llvmtypes.h
     llvmfunctions.cpp
     llvmloopscope.h
+    llvmloopanalyzer.cpp
+    llvmloopanalyzer.h
     llvmcompilercontext.cpp
     llvmcompilercontext.h
     llvmexecutablecode.cpp
diff --git a/src/engine/internal/llvm/llvmloopanalyzer.cpp b/src/engine/internal/llvm/llvmloopanalyzer.cpp
new file mode 100644
index 00000000..21015b7d
--- /dev/null
+++ b/src/engine/internal/llvm/llvmloopanalyzer.cpp
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#include "llvmloopanalyzer.h"
+#include "llvminstruction.h"
+#include "llvmvariableptr.h"
+
+using namespace libscratchcpp;
+
+bool LLVMLoopAnalyzer::variableTypeChanges(LLVMVariablePtr *varPtr, LLVMInstruction *loopBody, Compiler::StaticType preLoopType) const
+{
+    if (!varPtr || !loopBody)
+        return false;
+
+    if (preLoopType == Compiler::StaticType::Unknown)
+        return true;
+
+    // Find the last write instruction
+    LLVMInstruction *lastVarWrite = nullptr;
+    LLVMInstruction *ins = loopBody;
+
+    while (ins && ins->type != LLVMInstruction::Type::EndLoop) {
+        // TODO: Handle nested loops
+        if (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var)
+            lastVarWrite = ins;
+
+        ins = ins->next;
+    }
+
+    // Loops must always have an end instruction
+    assert(ins);
+
+    // Check the last write instruction, if any
+    return lastVarWrite ? !typesMatch(lastVarWrite, preLoopType) : false;
+}
+
+Compiler::StaticType LLVMLoopAnalyzer::optimizeRegisterType(LLVMRegister *reg) const
+{
+    // TODO: Move this method out if it's used in LLVMCodeBuilder too
+    assert(reg);
+
+    Compiler::StaticType ret = reg->type();
+
+    // Optimize string constants that represent numbers
+    if (reg->isConst() && reg->type() == Compiler::StaticType::String && reg->constValue().isValidNumber())
+        ret = Compiler::StaticType::Number;
+
+    return ret;
+}
+
+bool LLVMLoopAnalyzer::typesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const
+{
+    assert(ins);
+    assert(!ins->args.empty());
+    const auto arg = ins->args.back().second; // value is always the last argument in variable/list write instructions
+    auto argIns = arg->instruction;
+
+    // TODO: Handle cross-variable dependencies
+    /*if (argIns && (argIns->type == LLVMInstruction::Type::ReadVariable || argIns->type == LLVMInstruction::Type::GetListItem))
+        return isVarOrListTypeSafe(argIns.get(), expectedType, log, c);*/
+
+    return (optimizeRegisterType(arg) == expectedType);
+}
diff --git a/src/engine/internal/llvm/llvmloopanalyzer.h b/src/engine/internal/llvm/llvmloopanalyzer.h
new file mode 100644
index 00000000..f5a4e875
--- /dev/null
+++ b/src/engine/internal/llvm/llvmloopanalyzer.h
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#include <scratchcpp/compiler.h>
+
+namespace libscratchcpp
+{
+
+struct LLVMVariablePtr;
+struct LLVMInstruction;
+struct LLVMRegister;
+
+class LLVMLoopAnalyzer
+{
+    public:
+        bool variableTypeChanges(LLVMVariablePtr *varPtr, LLVMInstruction *loopBody, Compiler::StaticType preLoopType) const;
+
+    private:
+        Compiler::StaticType optimizeRegisterType(LLVMRegister *reg) const;
+        bool typesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const;
+};
+
+} // namespace libscratchcpp
diff --git a/test/llvm/CMakeLists.txt b/test/llvm/CMakeLists.txt
index 02337d23..52e13a80 100644
--- a/test/llvm/CMakeLists.txt
+++ b/test/llvm/CMakeLists.txt
@@ -20,6 +20,7 @@ add_executable(
   llvmexecutablecode_test.cpp
   llvmcodebuilder_test.cpp
   llvminstructionlist_test.cpp
+  loop_analyzer/variabletypechanges_test.cpp
 )
 
 target_link_libraries(
diff --git a/test/llvm/loop_analyzer/variabletypechanges_test.cpp b/test/llvm/loop_analyzer/variabletypechanges_test.cpp
new file mode 100644
index 00000000..c52dbe80
--- /dev/null
+++ b/test/llvm/loop_analyzer/variabletypechanges_test.cpp
@@ -0,0 +1,570 @@
+#include <scratchcpp/variable.h>
+#include <engine/internal/llvm/llvmloopanalyzer.h>
+#include <engine/internal/llvm/llvmvariableptr.h>
+#include <engine/internal/llvm/llvminstruction.h>
+#include <engine/internal/llvm/llvminstructionlist.h>
+#include <engine/internal/llvm/llvmconstantregister.h>
+#include <gtest/gtest.h>
+
+using namespace libscratchcpp;
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, NullParams)
+{
+    LLVMLoopAnalyzer analyzer;
+    ASSERT_FALSE(analyzer.variableTypeChanges(nullptr, nullptr, Compiler::StaticType::Number));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, NullVariable)
+{
+    LLVMLoopAnalyzer analyzer;
+
+    LLVMInstruction funcCall(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    LLVMInstruction end(LLVMInstruction::Type::EndLoop, nullptr, false);
+    funcCall.next = &end;
+    end.previous = &funcCall;
+
+    ASSERT_FALSE(analyzer.variableTypeChanges(nullptr, &funcCall, Compiler::StaticType::Number));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, NullLoopBody)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMVariablePtr varPtr;
+    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, nullptr, Compiler::StaticType::Number));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, EmptyLoop)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMVariablePtr varPtr;
+    LLVMInstruction ins(LLVMInstruction::Type::EndLoop, nullptr, false);
+
+    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, &ins, Compiler::StaticType::Number));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, EmptyLoopUnknownType)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMVariablePtr varPtr;
+    LLVMInstruction ins(LLVMInstruction::Type::EndLoop, nullptr, false);
+
+    // Always returns true for unknown type
+    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, &ins, Compiler::StaticType::Unknown));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, NoWriteOperations)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, funcCall.get(), Compiler::StaticType::Number));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeNumber)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 1.25);
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Number));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeBool)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Bool, true);
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Bool));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeString)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::String));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteStringOptimization)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "1.25");
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    // Although string is assigned, it's constant and represents a number
+    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Number));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteMultipleVariables)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var1("", "");
+    Variable var2("", "");
+    varPtr.var = &var1;
+
+    // Set var1
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 6);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Set var2
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    setVar2->workVariable = &var2;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar1.get(), Compiler::StaticType::Number));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteFromUnknownType)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMRegister value(Compiler::StaticType::Unknown);
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    // Always returns true for unknown type
+    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Number));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteToUnknownType)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 5);
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    // Always returns true for unknown type
+    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Unknown));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteUnknownToUnknownType)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMRegister value(Compiler::StaticType::Unknown);
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    // Always returns true for unknown type
+    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Unknown));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeNumberToString)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Number));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeStringToNumber)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 5.8);
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::String));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeNumberToBool)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Bool, true);
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Number));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeBoolToNumber)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 1);
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Bool));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeBoolToString)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "abc");
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Bool));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeStringToBool)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Bool, false);
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::String));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeNumber)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    // First write: string "abc" (incompatible with Number)
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "abc");
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Second write: number 5.25 (compatible with Number pre-loop type)
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 5.25);
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    // Should return false because final assignment is compatible with pre-loop Number type
+    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar1.get(), Compiler::StaticType::Number));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeString)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    // First write: number 42 (incompatible with String)
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Second write: string "hello" (compatible with String pre-loop type)
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "hello");
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    // Should return false because final assignment is compatible with pre-loop String type
+    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar1.get(), Compiler::StaticType::String));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeUnknown)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    // First write: unknown type
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMRegister value1(Compiler::StaticType::Unknown);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Second write: string "hello" (compatible with String pre-loop type)
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "hello");
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    // Should return false because final assignment is compatible with pre-loop String type
+    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar1.get(), Compiler::StaticType::String));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesWithStringOptimization)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    // First write: string "abc" (incompatible with Number)
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "abc");
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Second write: string "3.14" (optimized to Number, compatible with pre-loop type)
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "3.14");
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    // Should return false because final assignment is optimized to Number type
+    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar1.get(), Compiler::StaticType::Number));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesNumberToString)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    // First write: number 42 (compatible with Number)
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Second write: string "hello" (incompatible with Number pre-loop type)
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "hello");
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    // Should return true because final assignment is incompatible with pre-loop Number type
+    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar1.get(), Compiler::StaticType::Number));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToNumber)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 42.5);
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Bool));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToString)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "hello");
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Bool));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToStringNumberOptimization)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "3.14");
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    // String "3.14" gets optimized to Number, which is still different from Bool
+    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Bool));
+}
+
+// TODO: Handle nested loops
+// TODO: Handle cross-variable dependencies

From 5c9f495d9d15888883e0161a8d4f1e18c138f08a Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Wed, 23 Jul 2025 16:46:50 +0200
Subject: [PATCH 17/79] LLVMLoopAnalyzer: Implement nested loops in
 variableTypeChanges()

---
 src/engine/internal/llvm/llvmloopanalyzer.cpp |  80 ++-
 src/engine/internal/llvm/llvmloopanalyzer.h   |   4 +
 .../variabletypechanges_test.cpp              | 468 ++++++++++++++++--
 3 files changed, 514 insertions(+), 38 deletions(-)

diff --git a/src/engine/internal/llvm/llvmloopanalyzer.cpp b/src/engine/internal/llvm/llvmloopanalyzer.cpp
index 21015b7d..97b0b178 100644
--- a/src/engine/internal/llvm/llvmloopanalyzer.cpp
+++ b/src/engine/internal/llvm/llvmloopanalyzer.cpp
@@ -6,6 +6,9 @@
 
 using namespace libscratchcpp;
 
+static const std::unordered_set<LLVMInstruction::Type>
+    BEGIN_LOOP_INSTRUCTIONS = { LLVMInstruction::Type::BeginRepeatLoop, LLVMInstruction::Type::BeginWhileLoop, LLVMInstruction::Type::BeginRepeatUntilLoop };
+
 bool LLVMLoopAnalyzer::variableTypeChanges(LLVMVariablePtr *varPtr, LLVMInstruction *loopBody, Compiler::StaticType preLoopType) const
 {
     if (!varPtr || !loopBody)
@@ -14,23 +17,80 @@ bool LLVMLoopAnalyzer::variableTypeChanges(LLVMVariablePtr *varPtr, LLVMInstruct
     if (preLoopType == Compiler::StaticType::Unknown)
         return true;
 
-    // Find the last write instruction
-    LLVMInstruction *lastVarWrite = nullptr;
-    LLVMInstruction *ins = loopBody;
+    // Find loop end
+    LLVMInstruction *ins = loopBody->next;
+    int loopLevel = 0;
 
-    while (ins && ins->type != LLVMInstruction::Type::EndLoop) {
-        // TODO: Handle nested loops
-        if (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var)
-            lastVarWrite = ins;
+    while (ins && !(isLoopEnd(ins) && loopLevel == 0)) {
+        if (isLoopStart(ins))
+            loopLevel++;
+        else if (isLoopEnd(ins)) {
+            assert(loopLevel > 0);
+            loopLevel--;
+        }
 
         ins = ins->next;
     }
 
     // Loops must always have an end instruction
-    assert(ins);
+    if (!ins) {
+        assert(false);
+        return true;
+    }
 
-    // Check the last write instruction, if any
-    return lastVarWrite ? !typesMatch(lastVarWrite, preLoopType) : false;
+    return variableTypeChangesFromEnd(varPtr, ins, preLoopType);
+}
+
+bool LLVMLoopAnalyzer::variableTypeChangesFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *loopEnd, Compiler::StaticType preLoopType) const
+{
+    // Find the last write instruction
+    LLVMInstruction *ins = loopEnd->previous;
+
+    while (ins && !isLoopStart(ins)) {
+        if (isLoopEnd(ins)) {
+            // Nested loop
+            if (variableTypeChangesFromEnd(varPtr, ins, preLoopType))
+                return true;
+
+            // Skip the loop
+            int loopLevel = 0;
+            ins = ins->previous;
+
+            while (ins && !(isLoopStart(ins) && loopLevel == 0)) {
+                if (isLoopStart(ins)) {
+                    assert(loopLevel > 0);
+                    loopLevel--;
+                }
+
+                if (isLoopEnd(ins))
+                    loopLevel++;
+
+                ins = ins->previous;
+            };
+
+            if (!ins) {
+                assert(false);
+                return true;
+            }
+        } else if (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var) {
+            // Variable write instruction
+            return !typesMatch(ins, preLoopType);
+        }
+
+        ins = ins->previous;
+    }
+
+    return false;
+}
+
+bool LLVMLoopAnalyzer::isLoopStart(LLVMInstruction *ins) const
+{
+    return (BEGIN_LOOP_INSTRUCTIONS.find(ins->type) != BEGIN_LOOP_INSTRUCTIONS.cend());
+}
+
+bool LLVMLoopAnalyzer::isLoopEnd(LLVMInstruction *ins) const
+{
+    return (ins->type == LLVMInstruction::Type::EndLoop);
 }
 
 Compiler::StaticType LLVMLoopAnalyzer::optimizeRegisterType(LLVMRegister *reg) const
diff --git a/src/engine/internal/llvm/llvmloopanalyzer.h b/src/engine/internal/llvm/llvmloopanalyzer.h
index f5a4e875..9d8c11dc 100644
--- a/src/engine/internal/llvm/llvmloopanalyzer.h
+++ b/src/engine/internal/llvm/llvmloopanalyzer.h
@@ -15,6 +15,10 @@ class LLVMLoopAnalyzer
         bool variableTypeChanges(LLVMVariablePtr *varPtr, LLVMInstruction *loopBody, Compiler::StaticType preLoopType) const;
 
     private:
+        bool variableTypeChangesFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *loopEnd, Compiler::StaticType preLoopType) const;
+        bool isLoopStart(LLVMInstruction *ins) const;
+        bool isLoopEnd(LLVMInstruction *ins) const;
+
         Compiler::StaticType optimizeRegisterType(LLVMRegister *reg) const;
         bool typesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const;
 };
diff --git a/test/llvm/loop_analyzer/variabletypechanges_test.cpp b/test/llvm/loop_analyzer/variabletypechanges_test.cpp
index c52dbe80..c29534ac 100644
--- a/test/llvm/loop_analyzer/variabletypechanges_test.cpp
+++ b/test/llvm/loop_analyzer/variabletypechanges_test.cpp
@@ -37,19 +37,31 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, EmptyLoop)
 {
     LLVMLoopAnalyzer analyzer;
     LLVMVariablePtr varPtr;
-    LLVMInstruction ins(LLVMInstruction::Type::EndLoop, nullptr, false);
+    LLVMInstructionList list;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
 
-    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, &ins, Compiler::StaticType::Number));
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
 TEST(LLVMLoopAnalyzer_VariableTypeChanges, EmptyLoopUnknownType)
 {
     LLVMLoopAnalyzer analyzer;
     LLVMVariablePtr varPtr;
-    LLVMInstruction ins(LLVMInstruction::Type::EndLoop, nullptr, false);
+    LLVMInstructionList list;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
 
     // Always returns true for unknown type
-    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, &ins, Compiler::StaticType::Unknown));
+    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Unknown));
 }
 
 TEST(LLVMLoopAnalyzer_VariableTypeChanges, NoWriteOperations)
@@ -58,13 +70,16 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, NoWriteOperations)
     LLVMInstructionList list;
     LLVMVariablePtr varPtr;
 
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
     auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
     list.addInstruction(funcCall);
 
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, funcCall.get(), Compiler::StaticType::Number));
+    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
 TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeNumber)
@@ -75,6 +90,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeNumber)
     Variable var("", "");
     varPtr.var = &var;
 
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
     auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 1.25);
     setVar->workVariable = &var;
@@ -84,7 +102,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeNumber)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Number));
+    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
 TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeBool)
@@ -95,6 +113,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeBool)
     Variable var("", "");
     varPtr.var = &var;
 
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
     auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
     LLVMConstantRegister value(Compiler::StaticType::Bool, true);
     setVar->workVariable = &var;
@@ -104,7 +125,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeBool)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Bool));
+    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Bool));
 }
 
 TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeString)
@@ -115,6 +136,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeString)
     Variable var("", "");
     varPtr.var = &var;
 
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
     auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     setVar->workVariable = &var;
@@ -124,7 +148,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeString)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::String));
+    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::String));
 }
 
 TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteStringOptimization)
@@ -135,6 +159,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteStringOptimization)
     Variable var("", "");
     varPtr.var = &var;
 
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
     auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "1.25");
     setVar->workVariable = &var;
@@ -145,7 +172,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteStringOptimization)
     list.addInstruction(end);
 
     // Although string is assigned, it's constant and represents a number
-    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Number));
+    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
 TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteMultipleVariables)
@@ -157,6 +184,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteMultipleVariables)
     Variable var2("", "");
     varPtr.var = &var1;
 
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
     // Set var1
     auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 6);
@@ -174,7 +204,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteMultipleVariables)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar1.get(), Compiler::StaticType::Number));
+    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
 TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteFromUnknownType)
@@ -185,6 +215,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteFromUnknownType)
     Variable var("", "");
     varPtr.var = &var;
 
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
     auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
     LLVMRegister value(Compiler::StaticType::Unknown);
     setVar->workVariable = &var;
@@ -195,7 +228,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteFromUnknownType)
     list.addInstruction(end);
 
     // Always returns true for unknown type
-    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Number));
+    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
 TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteToUnknownType)
@@ -206,6 +239,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteToUnknownType)
     Variable var("", "");
     varPtr.var = &var;
 
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
     auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 5);
     setVar->workVariable = &var;
@@ -216,7 +252,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteToUnknownType)
     list.addInstruction(end);
 
     // Always returns true for unknown type
-    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Unknown));
+    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Unknown));
 }
 
 TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteUnknownToUnknownType)
@@ -227,6 +263,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteUnknownToUnknownType)
     Variable var("", "");
     varPtr.var = &var;
 
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
     auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
     LLVMRegister value(Compiler::StaticType::Unknown);
     setVar->workVariable = &var;
@@ -237,7 +276,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteUnknownToUnknownType)
     list.addInstruction(end);
 
     // Always returns true for unknown type
-    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Unknown));
+    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Unknown));
 }
 
 TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeNumberToString)
@@ -248,6 +287,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeNumberToStrin
     Variable var("", "");
     varPtr.var = &var;
 
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
     auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     setVar->workVariable = &var;
@@ -257,7 +299,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeNumberToStrin
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Number));
+    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
 TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeStringToNumber)
@@ -268,6 +310,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeStringToNumbe
     Variable var("", "");
     varPtr.var = &var;
 
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
     auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 5.8);
     setVar->workVariable = &var;
@@ -277,7 +322,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeStringToNumbe
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::String));
+    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::String));
 }
 
 TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeNumberToBool)
@@ -288,6 +333,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeNumberToBool)
     Variable var("", "");
     varPtr.var = &var;
 
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
     auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
     LLVMConstantRegister value(Compiler::StaticType::Bool, true);
     setVar->workVariable = &var;
@@ -297,7 +345,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeNumberToBool)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Number));
+    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
 TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeBoolToNumber)
@@ -308,6 +356,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeBoolToNumber)
     Variable var("", "");
     varPtr.var = &var;
 
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
     auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 1);
     setVar->workVariable = &var;
@@ -317,7 +368,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeBoolToNumber)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Bool));
+    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Bool));
 }
 
 TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeBoolToString)
@@ -328,6 +379,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeBoolToString)
     Variable var("", "");
     varPtr.var = &var;
 
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
     auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "abc");
     setVar->workVariable = &var;
@@ -337,7 +391,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeBoolToString)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Bool));
+    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Bool));
 }
 
 TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeStringToBool)
@@ -348,6 +402,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeStringToBool)
     Variable var("", "");
     varPtr.var = &var;
 
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
     auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
     LLVMConstantRegister value(Compiler::StaticType::Bool, false);
     setVar->workVariable = &var;
@@ -357,7 +414,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeStringToBool)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::String));
+    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::String));
 }
 
 TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeNumber)
@@ -368,6 +425,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeNumber)
     Variable var("", "");
     varPtr.var = &var;
 
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
     // First write: string "abc" (incompatible with Number)
     auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "abc");
@@ -386,7 +446,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeNumber)
     list.addInstruction(end);
 
     // Should return false because final assignment is compatible with pre-loop Number type
-    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar1.get(), Compiler::StaticType::Number));
+    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
 TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeString)
@@ -397,6 +457,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeString)
     Variable var("", "");
     varPtr.var = &var;
 
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
     // First write: number 42 (incompatible with String)
     auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
@@ -415,7 +478,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeString)
     list.addInstruction(end);
 
     // Should return false because final assignment is compatible with pre-loop String type
-    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar1.get(), Compiler::StaticType::String));
+    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::String));
 }
 
 TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeUnknown)
@@ -426,6 +489,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeUnknown)
     Variable var("", "");
     varPtr.var = &var;
 
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
     // First write: unknown type
     auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
     LLVMRegister value1(Compiler::StaticType::Unknown);
@@ -444,7 +510,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeUnknown)
     list.addInstruction(end);
 
     // Should return false because final assignment is compatible with pre-loop String type
-    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar1.get(), Compiler::StaticType::String));
+    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::String));
 }
 
 TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesWithStringOptimization)
@@ -455,6 +521,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesWithStringOptimization)
     Variable var("", "");
     varPtr.var = &var;
 
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
     // First write: string "abc" (incompatible with Number)
     auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "abc");
@@ -473,7 +542,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesWithStringOptimization)
     list.addInstruction(end);
 
     // Should return false because final assignment is optimized to Number type
-    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, setVar1.get(), Compiler::StaticType::Number));
+    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
 TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesNumberToString)
@@ -484,6 +553,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesNumberToString)
     Variable var("", "");
     varPtr.var = &var;
 
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
     // First write: number 42 (compatible with Number)
     auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
@@ -502,7 +574,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesNumberToString)
     list.addInstruction(end);
 
     // Should return true because final assignment is incompatible with pre-loop Number type
-    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar1.get(), Compiler::StaticType::Number));
+    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
 TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToNumber)
@@ -513,6 +585,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToNumber)
     Variable var("", "");
     varPtr.var = &var;
 
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
     auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 42.5);
     setVar->workVariable = &var;
@@ -522,7 +597,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToNumber)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Bool));
+    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Bool));
 }
 
 TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToString)
@@ -533,6 +608,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToString)
     Variable var("", "");
     varPtr.var = &var;
 
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
     auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "hello");
     setVar->workVariable = &var;
@@ -542,7 +620,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToString)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Bool));
+    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Bool));
 }
 
 TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToStringNumberOptimization)
@@ -553,6 +631,9 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToStringNumberOptim
     Variable var("", "");
     varPtr.var = &var;
 
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
     auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "3.14");
     setVar->workVariable = &var;
@@ -563,8 +644,339 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToStringNumberOptim
     list.addInstruction(end);
 
     // String "3.14" gets optimized to Number, which is still different from Bool
-    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, setVar.get(), Compiler::StaticType::Bool));
+    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Bool));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, NestedLoopWithTypeChange)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(outerLoop);
+
+    // Variable write inside outer loop
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Inner loop begin
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(innerLoop);
+
+    // Variable write inside inner loop
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    // Inner loop end
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(innerEnd);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(outerEnd);
+
+    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, NestedLoopWithoutTypeChange)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginWhileLoop, nullptr, false);
+    list.addInstruction(outerLoop);
+
+    // Variable write inside outer loop
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Inner loop begin
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(innerLoop);
+
+    // Variable write inside inner loop
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 2.5);
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    // Inner loop end
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(innerEnd);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(outerEnd);
+
+    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, NestedLoopTypeChangesButResets)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(outerLoop);
+
+    // Variable write inside outer loop
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Inner loop begin
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false);
+    list.addInstruction(innerLoop);
+
+    // Variable write inside inner loop
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    // Inner loop end
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(innerEnd);
+
+    // Variable write after inner loop - resets type
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value3(Compiler::StaticType::Number, 2);
+    setVar3->workVariable = &var;
+    setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    list.addInstruction(setVar3);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(outerEnd);
+
+    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, NestedLoopTypeChangesAndDoesNotReset)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(outerLoop);
+
+    // Variable write inside outer loop
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Inner loop begin
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginWhileLoop, nullptr, false);
+    list.addInstruction(innerLoop);
+
+    // Variable write inside inner loop
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    // Inner loop end
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(innerEnd);
+
+    // Variable write after inner loop - keeps the different type
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value3(Compiler::StaticType::String, "abc");
+    setVar3->workVariable = &var;
+    setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    list.addInstruction(setVar3);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(outerEnd);
+
+    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, NestedLoopWithTypeChangeBeforeLoop)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false);
+    list.addInstruction(outerLoop);
+
+    // Variable write inside outer loop
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "test");
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Inner loop begin
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(innerLoop);
+
+    // Variable write inside inner loop
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 5);
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    // Inner loop end
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(innerEnd);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(outerEnd);
+
+    // Returns true because loops can be skipped
+    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleNestedLoopsWithTypeChange)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(outerLoop);
+
+    // Variable write inside outer loop
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Inner loop 1 begin
+    auto innerLoop1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(innerLoop1);
+
+    // Variable write inside inner loop 1
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75);
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    // Inner loop 2 begin
+    auto innerLoop2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(innerLoop2);
+
+    // Variable write inside inner loop 2
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value3(Compiler::StaticType::String, "abc");
+    setVar3->workVariable = &var;
+    setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    list.addInstruction(setVar3);
+
+    // Inner loop 2 end
+    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(innerEnd2);
+
+    // Inner loop 1 end
+    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(innerEnd1);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(outerEnd);
+
+    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleNestedLoopsWithTypeChangeButTypeReset)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(outerLoop);
+
+    // Variable write inside outer loop
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Inner loop 1 begin
+    auto innerLoop1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(innerLoop1);
+
+    // Inner loop 2 begin
+    auto innerLoop2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(innerLoop2);
+
+    // Variable write inside inner loop 2
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value3(Compiler::StaticType::String, "abc");
+    setVar3->workVariable = &var;
+    setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    list.addInstruction(setVar3);
+
+    // Inner loop 2 end
+    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(innerEnd2);
+
+    // Variable write inside inner loop 1 - resets type
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75);
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    // Inner loop 1 end
+    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(innerEnd1);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(outerEnd);
+
+    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
 }
 
-// TODO: Handle nested loops
 // TODO: Handle cross-variable dependencies

From 5b0c7701706f8f4b7be9f857934e76ebf84e4359 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Wed, 23 Jul 2025 17:50:20 +0200
Subject: [PATCH 18/79] LLVMLoopAnalyzer: Handle if statements in
 variableTypeChanges()

---
 src/engine/internal/llvm/llvmloopanalyzer.cpp |  35 +++--
 src/engine/internal/llvm/llvmloopanalyzer.h   |   3 +
 .../variabletypechanges_test.cpp              | 122 ++++++++++++++++++
 3 files changed, 150 insertions(+), 10 deletions(-)

diff --git a/src/engine/internal/llvm/llvmloopanalyzer.cpp b/src/engine/internal/llvm/llvmloopanalyzer.cpp
index 97b0b178..7ae76cfb 100644
--- a/src/engine/internal/llvm/llvmloopanalyzer.cpp
+++ b/src/engine/internal/llvm/llvmloopanalyzer.cpp
@@ -47,23 +47,23 @@ bool LLVMLoopAnalyzer::variableTypeChangesFromEnd(LLVMVariablePtr *varPtr, LLVMI
     LLVMInstruction *ins = loopEnd->previous;
 
     while (ins && !isLoopStart(ins)) {
-        if (isLoopEnd(ins)) {
-            // Nested loop
+        if (isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) {
+            // Nested loop or if statement
             if (variableTypeChangesFromEnd(varPtr, ins, preLoopType))
                 return true;
 
-            // Skip the loop
-            int loopLevel = 0;
+            // Skip the loop or if statement
+            int level = 0;
             ins = ins->previous;
 
-            while (ins && !(isLoopStart(ins) && loopLevel == 0)) {
-                if (isLoopStart(ins)) {
-                    assert(loopLevel > 0);
-                    loopLevel--;
+            while (ins && !((isLoopStart(ins) || isIfStart(ins) || isElse(ins)) && level == 0)) {
+                if (isLoopStart(ins) || isIfStart(ins)) {
+                    assert(level > 0);
+                    level--;
                 }
 
-                if (isLoopEnd(ins))
-                    loopLevel++;
+                if (isLoopEnd(ins) || isIfEnd(ins) || isElse(ins))
+                    level++;
 
                 ins = ins->previous;
             };
@@ -93,6 +93,21 @@ bool LLVMLoopAnalyzer::isLoopEnd(LLVMInstruction *ins) const
     return (ins->type == LLVMInstruction::Type::EndLoop);
 }
 
+bool LLVMLoopAnalyzer::isIfStart(LLVMInstruction *ins) const
+{
+    return (ins->type == LLVMInstruction::Type::BeginIf);
+}
+
+bool LLVMLoopAnalyzer::isElse(LLVMInstruction *ins) const
+{
+    return (ins->type == LLVMInstruction::Type::BeginElse);
+}
+
+bool LLVMLoopAnalyzer::isIfEnd(LLVMInstruction *ins) const
+{
+    return (ins->type == LLVMInstruction::Type::EndIf);
+}
+
 Compiler::StaticType LLVMLoopAnalyzer::optimizeRegisterType(LLVMRegister *reg) const
 {
     // TODO: Move this method out if it's used in LLVMCodeBuilder too
diff --git a/src/engine/internal/llvm/llvmloopanalyzer.h b/src/engine/internal/llvm/llvmloopanalyzer.h
index 9d8c11dc..27d81310 100644
--- a/src/engine/internal/llvm/llvmloopanalyzer.h
+++ b/src/engine/internal/llvm/llvmloopanalyzer.h
@@ -18,6 +18,9 @@ class LLVMLoopAnalyzer
         bool variableTypeChangesFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *loopEnd, Compiler::StaticType preLoopType) const;
         bool isLoopStart(LLVMInstruction *ins) const;
         bool isLoopEnd(LLVMInstruction *ins) const;
+        bool isIfStart(LLVMInstruction *ins) const;
+        bool isElse(LLVMInstruction *ins) const;
+        bool isIfEnd(LLVMInstruction *ins) const;
 
         Compiler::StaticType optimizeRegisterType(LLVMRegister *reg) const;
         bool typesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const;
diff --git a/test/llvm/loop_analyzer/variabletypechanges_test.cpp b/test/llvm/loop_analyzer/variabletypechanges_test.cpp
index c29534ac..8ddad887 100644
--- a/test/llvm/loop_analyzer/variabletypechanges_test.cpp
+++ b/test/llvm/loop_analyzer/variabletypechanges_test.cpp
@@ -647,6 +647,128 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToStringNumberOptim
     ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Bool));
 }
 
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, TypeChangeInIfBranch)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(ifStart);
+
+    // First write - changes type
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "test");
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    list.addInstruction(elseStart);
+
+    // Second write - does not change type
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 42);
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(ifEnd);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    // Returns true because the type-changing branch might run
+    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, TypeChangeInElseBranch)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(ifStart);
+
+    // First write - does not change type
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    list.addInstruction(elseStart);
+
+    // Second write - changes type
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(ifEnd);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    // Returns true because the type-changing branch might run
+    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number));
+}
+
+TEST(LLVMLoopAnalyzer_VariableTypeChanges, IfElseWithoutTypeChange)
+{
+    LLVMLoopAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(ifStart);
+
+    // First write - does not change type
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    list.addInstruction(elseStart);
+
+    // Second write - does not change type
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25);
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(ifEnd);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number));
+}
+
 TEST(LLVMLoopAnalyzer_VariableTypeChanges, NestedLoopWithTypeChange)
 {
     LLVMLoopAnalyzer analyzer;

From 9c43261348e08bbd2c5f450b21a2a091e58933e4 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Thu, 24 Jul 2025 14:47:09 +0200
Subject: [PATCH 19/79] LLVMLoopAnalyzer: Fix null variable test case for
 variableTypeChanges()

---
 .../loop_analyzer/variabletypechanges_test.cpp    | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/test/llvm/loop_analyzer/variabletypechanges_test.cpp b/test/llvm/loop_analyzer/variabletypechanges_test.cpp
index 8ddad887..abfa95a7 100644
--- a/test/llvm/loop_analyzer/variabletypechanges_test.cpp
+++ b/test/llvm/loop_analyzer/variabletypechanges_test.cpp
@@ -17,13 +17,18 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, NullParams)
 TEST(LLVMLoopAnalyzer_VariableTypeChanges, NullVariable)
 {
     LLVMLoopAnalyzer analyzer;
+    LLVMInstructionList list;
 
-    LLVMInstruction funcCall(LLVMInstruction::Type::FunctionCall, nullptr, false);
-    LLVMInstruction end(LLVMInstruction::Type::EndLoop, nullptr, false);
-    funcCall.next = &end;
-    end.previous = &funcCall;
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChanges(nullptr, &funcCall, Compiler::StaticType::Number));
+    ASSERT_FALSE(analyzer.variableTypeChanges(nullptr, start.get(), Compiler::StaticType::Number));
 }
 
 TEST(LLVMLoopAnalyzer_VariableTypeChanges, NullLoopBody)

From 33b37d6932537abf7cee0f42a767a37e3ba19f78 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Thu, 24 Jul 2025 14:49:42 +0200
Subject: [PATCH 20/79] LLVMLoopAnalyzer: Get write value type from a separate
 method

---
 src/engine/internal/llvm/llvmloopanalyzer.cpp | 11 ++++++++---
 src/engine/internal/llvm/llvmloopanalyzer.h   |  1 +
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/src/engine/internal/llvm/llvmloopanalyzer.cpp b/src/engine/internal/llvm/llvmloopanalyzer.cpp
index 7ae76cfb..ce38d4f0 100644
--- a/src/engine/internal/llvm/llvmloopanalyzer.cpp
+++ b/src/engine/internal/llvm/llvmloopanalyzer.cpp
@@ -122,16 +122,21 @@ Compiler::StaticType LLVMLoopAnalyzer::optimizeRegisterType(LLVMRegister *reg) c
     return ret;
 }
 
-bool LLVMLoopAnalyzer::typesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const
+Compiler::StaticType LLVMLoopAnalyzer::writeValueType(LLVMInstruction *ins) const
 {
     assert(ins);
     assert(!ins->args.empty());
     const auto arg = ins->args.back().second; // value is always the last argument in variable/list write instructions
-    auto argIns = arg->instruction;
+    return optimizeRegisterType(arg);
+}
+
+bool LLVMLoopAnalyzer::typesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const
+{
+    // auto argIns = arg->instruction;
 
     // TODO: Handle cross-variable dependencies
     /*if (argIns && (argIns->type == LLVMInstruction::Type::ReadVariable || argIns->type == LLVMInstruction::Type::GetListItem))
         return isVarOrListTypeSafe(argIns.get(), expectedType, log, c);*/
 
-    return (optimizeRegisterType(arg) == expectedType);
+    return (writeValueType(ins) == expectedType);
 }
diff --git a/src/engine/internal/llvm/llvmloopanalyzer.h b/src/engine/internal/llvm/llvmloopanalyzer.h
index 27d81310..346d0053 100644
--- a/src/engine/internal/llvm/llvmloopanalyzer.h
+++ b/src/engine/internal/llvm/llvmloopanalyzer.h
@@ -23,6 +23,7 @@ class LLVMLoopAnalyzer
         bool isIfEnd(LLVMInstruction *ins) const;
 
         Compiler::StaticType optimizeRegisterType(LLVMRegister *reg) const;
+        Compiler::StaticType writeValueType(LLVMInstruction *ins) const;
         bool typesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const;
 };
 

From 2d6dc53028f5ad07a4866cdcee399770b3e58156 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Thu, 24 Jul 2025 15:10:17 +0200
Subject: [PATCH 21/79] LLVMLoopAnalyzer -> LLVMTypeAnalyzer

---
 src/engine/internal/llvm/CMakeLists.txt       |   4 +-
 ...mloopanalyzer.cpp => llvmtypeanalyzer.cpp} |  26 +-
 ...{llvmloopanalyzer.h => llvmtypeanalyzer.h} |   6 +-
 test/llvm/CMakeLists.txt                      |   2 +-
 .../variabletypechangesinloop_test.cpp}       | 230 +++++++++---------
 5 files changed, 134 insertions(+), 134 deletions(-)
 rename src/engine/internal/llvm/{llvmloopanalyzer.cpp => llvmtypeanalyzer.cpp} (78%)
 rename src/engine/internal/llvm/{llvmloopanalyzer.h => llvmtypeanalyzer.h} (71%)
 rename test/llvm/{loop_analyzer/variabletypechanges_test.cpp => type_analyzer/variabletypechangesinloop_test.cpp} (82%)

diff --git a/src/engine/internal/llvm/CMakeLists.txt b/src/engine/internal/llvm/CMakeLists.txt
index fb0617f4..afdcee56 100644
--- a/src/engine/internal/llvm/CMakeLists.txt
+++ b/src/engine/internal/llvm/CMakeLists.txt
@@ -17,8 +17,8 @@ target_sources(scratchcpp
     llvmtypes.h
     llvmfunctions.cpp
     llvmloopscope.h
-    llvmloopanalyzer.cpp
-    llvmloopanalyzer.h
+    llvmtypeanalyzer.cpp
+    llvmtypeanalyzer.h
     llvmcompilercontext.cpp
     llvmcompilercontext.h
     llvmexecutablecode.cpp
diff --git a/src/engine/internal/llvm/llvmloopanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
similarity index 78%
rename from src/engine/internal/llvm/llvmloopanalyzer.cpp
rename to src/engine/internal/llvm/llvmtypeanalyzer.cpp
index ce38d4f0..e043111d 100644
--- a/src/engine/internal/llvm/llvmloopanalyzer.cpp
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: Apache-2.0
 
-#include "llvmloopanalyzer.h"
+#include "llvmtypeanalyzer.h"
 #include "llvminstruction.h"
 #include "llvmvariableptr.h"
 
@@ -9,7 +9,7 @@ using namespace libscratchcpp;
 static const std::unordered_set<LLVMInstruction::Type>
     BEGIN_LOOP_INSTRUCTIONS = { LLVMInstruction::Type::BeginRepeatLoop, LLVMInstruction::Type::BeginWhileLoop, LLVMInstruction::Type::BeginRepeatUntilLoop };
 
-bool LLVMLoopAnalyzer::variableTypeChanges(LLVMVariablePtr *varPtr, LLVMInstruction *loopBody, Compiler::StaticType preLoopType) const
+bool LLVMTypeAnalyzer::variableTypeChangesInLoop(LLVMVariablePtr *varPtr, LLVMInstruction *loopBody, Compiler::StaticType preLoopType) const
 {
     if (!varPtr || !loopBody)
         return false;
@@ -38,10 +38,10 @@ bool LLVMLoopAnalyzer::variableTypeChanges(LLVMVariablePtr *varPtr, LLVMInstruct
         return true;
     }
 
-    return variableTypeChangesFromEnd(varPtr, ins, preLoopType);
+    return variableTypeChangesInLoopFromEnd(varPtr, ins, preLoopType);
 }
 
-bool LLVMLoopAnalyzer::variableTypeChangesFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *loopEnd, Compiler::StaticType preLoopType) const
+bool LLVMTypeAnalyzer::variableTypeChangesInLoopFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *loopEnd, Compiler::StaticType preLoopType) const
 {
     // Find the last write instruction
     LLVMInstruction *ins = loopEnd->previous;
@@ -49,7 +49,7 @@ bool LLVMLoopAnalyzer::variableTypeChangesFromEnd(LLVMVariablePtr *varPtr, LLVMI
     while (ins && !isLoopStart(ins)) {
         if (isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) {
             // Nested loop or if statement
-            if (variableTypeChangesFromEnd(varPtr, ins, preLoopType))
+            if (variableTypeChangesInLoopFromEnd(varPtr, ins, preLoopType))
                 return true;
 
             // Skip the loop or if statement
@@ -83,32 +83,32 @@ bool LLVMLoopAnalyzer::variableTypeChangesFromEnd(LLVMVariablePtr *varPtr, LLVMI
     return false;
 }
 
-bool LLVMLoopAnalyzer::isLoopStart(LLVMInstruction *ins) const
+bool LLVMTypeAnalyzer::isLoopStart(LLVMInstruction *ins) const
 {
     return (BEGIN_LOOP_INSTRUCTIONS.find(ins->type) != BEGIN_LOOP_INSTRUCTIONS.cend());
 }
 
-bool LLVMLoopAnalyzer::isLoopEnd(LLVMInstruction *ins) const
+bool LLVMTypeAnalyzer::isLoopEnd(LLVMInstruction *ins) const
 {
     return (ins->type == LLVMInstruction::Type::EndLoop);
 }
 
-bool LLVMLoopAnalyzer::isIfStart(LLVMInstruction *ins) const
+bool LLVMTypeAnalyzer::isIfStart(LLVMInstruction *ins) const
 {
     return (ins->type == LLVMInstruction::Type::BeginIf);
 }
 
-bool LLVMLoopAnalyzer::isElse(LLVMInstruction *ins) const
+bool LLVMTypeAnalyzer::isElse(LLVMInstruction *ins) const
 {
     return (ins->type == LLVMInstruction::Type::BeginElse);
 }
 
-bool LLVMLoopAnalyzer::isIfEnd(LLVMInstruction *ins) const
+bool LLVMTypeAnalyzer::isIfEnd(LLVMInstruction *ins) const
 {
     return (ins->type == LLVMInstruction::Type::EndIf);
 }
 
-Compiler::StaticType LLVMLoopAnalyzer::optimizeRegisterType(LLVMRegister *reg) const
+Compiler::StaticType LLVMTypeAnalyzer::optimizeRegisterType(LLVMRegister *reg) const
 {
     // TODO: Move this method out if it's used in LLVMCodeBuilder too
     assert(reg);
@@ -122,7 +122,7 @@ Compiler::StaticType LLVMLoopAnalyzer::optimizeRegisterType(LLVMRegister *reg) c
     return ret;
 }
 
-Compiler::StaticType LLVMLoopAnalyzer::writeValueType(LLVMInstruction *ins) const
+Compiler::StaticType LLVMTypeAnalyzer::writeValueType(LLVMInstruction *ins) const
 {
     assert(ins);
     assert(!ins->args.empty());
@@ -130,7 +130,7 @@ Compiler::StaticType LLVMLoopAnalyzer::writeValueType(LLVMInstruction *ins) cons
     return optimizeRegisterType(arg);
 }
 
-bool LLVMLoopAnalyzer::typesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const
+bool LLVMTypeAnalyzer::typesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const
 {
     // auto argIns = arg->instruction;
 
diff --git a/src/engine/internal/llvm/llvmloopanalyzer.h b/src/engine/internal/llvm/llvmtypeanalyzer.h
similarity index 71%
rename from src/engine/internal/llvm/llvmloopanalyzer.h
rename to src/engine/internal/llvm/llvmtypeanalyzer.h
index 346d0053..8049a503 100644
--- a/src/engine/internal/llvm/llvmloopanalyzer.h
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.h
@@ -9,13 +9,13 @@ struct LLVMVariablePtr;
 struct LLVMInstruction;
 struct LLVMRegister;
 
-class LLVMLoopAnalyzer
+class LLVMTypeAnalyzer
 {
     public:
-        bool variableTypeChanges(LLVMVariablePtr *varPtr, LLVMInstruction *loopBody, Compiler::StaticType preLoopType) const;
+        bool variableTypeChangesInLoop(LLVMVariablePtr *varPtr, LLVMInstruction *loopBody, Compiler::StaticType preLoopType) const;
 
     private:
-        bool variableTypeChangesFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *loopEnd, Compiler::StaticType preLoopType) const;
+        bool variableTypeChangesInLoopFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *loopEnd, Compiler::StaticType preLoopType) const;
         bool isLoopStart(LLVMInstruction *ins) const;
         bool isLoopEnd(LLVMInstruction *ins) const;
         bool isIfStart(LLVMInstruction *ins) const;
diff --git a/test/llvm/CMakeLists.txt b/test/llvm/CMakeLists.txt
index 52e13a80..bc1ccc75 100644
--- a/test/llvm/CMakeLists.txt
+++ b/test/llvm/CMakeLists.txt
@@ -20,7 +20,7 @@ add_executable(
   llvmexecutablecode_test.cpp
   llvmcodebuilder_test.cpp
   llvminstructionlist_test.cpp
-  loop_analyzer/variabletypechanges_test.cpp
+  type_analyzer/variabletypechangesinloop_test.cpp
 )
 
 target_link_libraries(
diff --git a/test/llvm/loop_analyzer/variabletypechanges_test.cpp b/test/llvm/type_analyzer/variabletypechangesinloop_test.cpp
similarity index 82%
rename from test/llvm/loop_analyzer/variabletypechanges_test.cpp
rename to test/llvm/type_analyzer/variabletypechangesinloop_test.cpp
index abfa95a7..c5befa24 100644
--- a/test/llvm/loop_analyzer/variabletypechanges_test.cpp
+++ b/test/llvm/type_analyzer/variabletypechangesinloop_test.cpp
@@ -1,5 +1,5 @@
 #include <scratchcpp/variable.h>
-#include <engine/internal/llvm/llvmloopanalyzer.h>
+#include <engine/internal/llvm/llvmtypeanalyzer.h>
 #include <engine/internal/llvm/llvmvariableptr.h>
 #include <engine/internal/llvm/llvminstruction.h>
 #include <engine/internal/llvm/llvminstructionlist.h>
@@ -8,15 +8,15 @@
 
 using namespace libscratchcpp;
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, NullParams)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NullParams)
 {
-    LLVMLoopAnalyzer analyzer;
-    ASSERT_FALSE(analyzer.variableTypeChanges(nullptr, nullptr, Compiler::StaticType::Number));
+    LLVMTypeAnalyzer analyzer;
+    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(nullptr, nullptr, Compiler::StaticType::Number));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, NullVariable)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NullVariable)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
@@ -28,19 +28,19 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, NullVariable)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChanges(nullptr, start.get(), Compiler::StaticType::Number));
+    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(nullptr, start.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, NullLoopBody)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NullLoopBody)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMVariablePtr varPtr;
-    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, nullptr, Compiler::StaticType::Number));
+    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, nullptr, Compiler::StaticType::Number));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, EmptyLoop)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, EmptyLoop)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMVariablePtr varPtr;
     LLVMInstructionList list;
 
@@ -50,12 +50,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, EmptyLoop)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, EmptyLoopUnknownType)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, EmptyLoopUnknownType)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMVariablePtr varPtr;
     LLVMInstructionList list;
 
@@ -66,12 +66,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, EmptyLoopUnknownType)
     list.addInstruction(end);
 
     // Always returns true for unknown type
-    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Unknown));
+    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Unknown));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, NoWriteOperations)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NoWriteOperations)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
     LLVMVariablePtr varPtr;
 
@@ -84,12 +84,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, NoWriteOperations)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeNumber)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteSameTypeNumber)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
     LLVMVariablePtr varPtr;
     Variable var("", "");
@@ -107,12 +107,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeNumber)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeBool)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteSameTypeBool)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
     LLVMVariablePtr varPtr;
     Variable var("", "");
@@ -130,12 +130,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeBool)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Bool));
+    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Bool));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeString)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteSameTypeString)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
     LLVMVariablePtr varPtr;
     Variable var("", "");
@@ -153,12 +153,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteSameTypeString)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::String));
+    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::String));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteStringOptimization)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteStringOptimization)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
     LLVMVariablePtr varPtr;
     Variable var("", "");
@@ -177,12 +177,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteStringOptimization)
     list.addInstruction(end);
 
     // Although string is assigned, it's constant and represents a number
-    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteMultipleVariables)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteMultipleVariables)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
     LLVMVariablePtr varPtr;
     Variable var1("", "");
@@ -209,12 +209,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteMultipleVariables)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteFromUnknownType)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteFromUnknownType)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
     LLVMVariablePtr varPtr;
     Variable var("", "");
@@ -233,12 +233,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteFromUnknownType)
     list.addInstruction(end);
 
     // Always returns true for unknown type
-    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteToUnknownType)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteToUnknownType)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
     LLVMVariablePtr varPtr;
     Variable var("", "");
@@ -257,12 +257,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteToUnknownType)
     list.addInstruction(end);
 
     // Always returns true for unknown type
-    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Unknown));
+    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Unknown));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteUnknownToUnknownType)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteUnknownToUnknownType)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
     LLVMVariablePtr varPtr;
     Variable var("", "");
@@ -281,12 +281,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteUnknownToUnknownType)
     list.addInstruction(end);
 
     // Always returns true for unknown type
-    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Unknown));
+    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Unknown));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeNumberToString)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeNumberToString)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
     LLVMVariablePtr varPtr;
     Variable var("", "");
@@ -304,12 +304,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeNumberToStrin
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeStringToNumber)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeStringToNumber)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
     LLVMVariablePtr varPtr;
     Variable var("", "");
@@ -327,12 +327,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeStringToNumbe
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::String));
+    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::String));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeNumberToBool)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeNumberToBool)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
     LLVMVariablePtr varPtr;
     Variable var("", "");
@@ -350,12 +350,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeNumberToBool)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeBoolToNumber)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeBoolToNumber)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
     LLVMVariablePtr varPtr;
     Variable var("", "");
@@ -373,12 +373,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeBoolToNumber)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Bool));
+    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Bool));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeBoolToString)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeBoolToString)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
     LLVMVariablePtr varPtr;
     Variable var("", "");
@@ -396,12 +396,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeBoolToString)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Bool));
+    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Bool));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeStringToBool)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeStringToBool)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
     LLVMVariablePtr varPtr;
     Variable var("", "");
@@ -419,12 +419,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, SingleWriteDifferentTypeStringToBool)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::String));
+    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::String));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeNumber)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesSameTypeNumber)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
     LLVMVariablePtr varPtr;
     Variable var("", "");
@@ -451,12 +451,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeNumber)
     list.addInstruction(end);
 
     // Should return false because final assignment is compatible with pre-loop Number type
-    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeString)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesSameTypeString)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
     LLVMVariablePtr varPtr;
     Variable var("", "");
@@ -483,12 +483,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeString)
     list.addInstruction(end);
 
     // Should return false because final assignment is compatible with pre-loop String type
-    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::String));
+    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::String));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeUnknown)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesSameTypeUnknown)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
     LLVMVariablePtr varPtr;
     Variable var("", "");
@@ -515,12 +515,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesSameTypeUnknown)
     list.addInstruction(end);
 
     // Should return false because final assignment is compatible with pre-loop String type
-    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::String));
+    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::String));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesWithStringOptimization)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesWithStringOptimization)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
     LLVMVariablePtr varPtr;
     Variable var("", "");
@@ -547,12 +547,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesWithStringOptimization)
     list.addInstruction(end);
 
     // Should return false because final assignment is optimized to Number type
-    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesNumberToString)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesNumberToString)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
     LLVMVariablePtr varPtr;
     Variable var("", "");
@@ -579,12 +579,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesNumberToString)
     list.addInstruction(end);
 
     // Should return true because final assignment is incompatible with pre-loop Number type
-    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToNumber)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesBoolToNumber)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
     LLVMVariablePtr varPtr;
     Variable var("", "");
@@ -602,12 +602,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToNumber)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Bool));
+    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Bool));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToString)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesBoolToString)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
     LLVMVariablePtr varPtr;
     Variable var("", "");
@@ -625,12 +625,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToString)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Bool));
+    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Bool));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToStringNumberOptimization)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesBoolToStringNumberOptimization)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
     LLVMVariablePtr varPtr;
     Variable var("", "");
@@ -649,12 +649,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleWritesBoolToStringNumberOptim
     list.addInstruction(end);
 
     // String "3.14" gets optimized to Number, which is still different from Bool
-    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Bool));
+    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Bool));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, TypeChangeInIfBranch)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, TypeChangeInIfBranch)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
     LLVMVariablePtr varPtr;
     Variable var("", "");
@@ -690,12 +690,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, TypeChangeInIfBranch)
     list.addInstruction(end);
 
     // Returns true because the type-changing branch might run
-    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, TypeChangeInElseBranch)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, TypeChangeInElseBranch)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
     LLVMVariablePtr varPtr;
     Variable var("", "");
@@ -731,12 +731,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, TypeChangeInElseBranch)
     list.addInstruction(end);
 
     // Returns true because the type-changing branch might run
-    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, IfElseWithoutTypeChange)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, IfElseWithoutTypeChange)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
     LLVMVariablePtr varPtr;
     Variable var("", "");
@@ -771,12 +771,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, IfElseWithoutTypeChange)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, NestedLoopWithTypeChange)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NestedLoopWithTypeChange)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
     LLVMVariablePtr varPtr;
     Variable var("", "");
@@ -812,12 +812,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, NestedLoopWithTypeChange)
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
+    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, NestedLoopWithoutTypeChange)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NestedLoopWithoutTypeChange)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
     LLVMVariablePtr varPtr;
     Variable var("", "");
@@ -853,12 +853,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, NestedLoopWithoutTypeChange)
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
+    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, NestedLoopTypeChangesButResets)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NestedLoopTypeChangesButResets)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
     LLVMVariablePtr varPtr;
     Variable var("", "");
@@ -901,12 +901,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, NestedLoopTypeChangesButResets)
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
+    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, NestedLoopTypeChangesAndDoesNotReset)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NestedLoopTypeChangesAndDoesNotReset)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
     LLVMVariablePtr varPtr;
     Variable var("", "");
@@ -949,12 +949,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, NestedLoopTypeChangesAndDoesNotReset)
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
+    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, NestedLoopWithTypeChangeBeforeLoop)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NestedLoopWithTypeChangeBeforeLoop)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
     LLVMVariablePtr varPtr;
     Variable var("", "");
@@ -991,12 +991,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, NestedLoopWithTypeChangeBeforeLoop)
     list.addInstruction(outerEnd);
 
     // Returns true because loops can be skipped
-    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
+    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleNestedLoopsWithTypeChange)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleNestedLoopsWithTypeChange)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
     LLVMVariablePtr varPtr;
     Variable var("", "");
@@ -1047,12 +1047,12 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleNestedLoopsWithTypeChange)
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_TRUE(analyzer.variableTypeChanges(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
+    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleNestedLoopsWithTypeChangeButTypeReset)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleNestedLoopsWithTypeChangeButTypeReset)
 {
-    LLVMLoopAnalyzer analyzer;
+    LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
     LLVMVariablePtr varPtr;
     Variable var("", "");
@@ -1103,7 +1103,7 @@ TEST(LLVMLoopAnalyzer_VariableTypeChanges, MultipleNestedLoopsWithTypeChangeButT
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_FALSE(analyzer.variableTypeChanges(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
+    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
 }
 
 // TODO: Handle cross-variable dependencies

From 26b2f6da725f0f17b54eca12451a7eb562921800 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Thu, 24 Jul 2025 16:12:34 +0200
Subject: [PATCH 22/79] LLVMTypeAnalyzer: Implement variableType() for basic
 cases

---
 src/engine/internal/llvm/llvmtypeanalyzer.cpp |  42 +
 src/engine/internal/llvm/llvmtypeanalyzer.h   |   1 +
 test/llvm/CMakeLists.txt                      |   1 +
 test/llvm/type_analyzer/variabletype_test.cpp | 994 ++++++++++++++++++
 4 files changed, 1038 insertions(+)
 create mode 100644 test/llvm/type_analyzer/variabletype_test.cpp

diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
index e043111d..f0e4c749 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
@@ -9,6 +9,48 @@ using namespace libscratchcpp;
 static const std::unordered_set<LLVMInstruction::Type>
     BEGIN_LOOP_INSTRUCTIONS = { LLVMInstruction::Type::BeginRepeatLoop, LLVMInstruction::Type::BeginWhileLoop, LLVMInstruction::Type::BeginRepeatUntilLoop };
 
+Compiler::StaticType LLVMTypeAnalyzer::variableType(LLVMVariablePtr *varPtr, LLVMInstruction *pos, Compiler::StaticType previousType) const
+{
+    if (!varPtr || !pos)
+        return Compiler::StaticType::Unknown;
+
+    // Check the last write operation before the instruction
+    LLVMInstruction *ins = pos;
+    LLVMInstruction *write = nullptr;
+    LLVMInstruction *loopStart = nullptr;
+    int level = 0;
+
+    while (ins) {
+        if (isLoopEnd(ins))
+            level++;
+        else if (isLoopStart(ins)) {
+            level--;
+
+            if (!loopStart)
+                loopStart = ins;
+        } else if (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var) {
+            if (level <= 0) { // ignore nested loops (they're handled later)
+                write = ins;
+                break;
+            }
+        }
+
+        ins = ins->previous;
+    }
+
+    if (loopStart) {
+        // Analyze the first loop that was found
+        if (variableTypeChangesInLoop(varPtr, loopStart, previousType))
+            return write ? writeValueType(write) : Compiler::StaticType::Unknown;
+    } else if (write) {
+        // There wasn't any loop found, so we can just check the last write operation
+        return writeValueType(write);
+    }
+
+    // No write operation found
+    return previousType;
+}
+
 bool LLVMTypeAnalyzer::variableTypeChangesInLoop(LLVMVariablePtr *varPtr, LLVMInstruction *loopBody, Compiler::StaticType preLoopType) const
 {
     if (!varPtr || !loopBody)
diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.h b/src/engine/internal/llvm/llvmtypeanalyzer.h
index 8049a503..86935282 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.h
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.h
@@ -12,6 +12,7 @@ struct LLVMRegister;
 class LLVMTypeAnalyzer
 {
     public:
+        Compiler::StaticType variableType(LLVMVariablePtr *varPtr, LLVMInstruction *pos, Compiler::StaticType previousType) const;
         bool variableTypeChangesInLoop(LLVMVariablePtr *varPtr, LLVMInstruction *loopBody, Compiler::StaticType preLoopType) const;
 
     private:
diff --git a/test/llvm/CMakeLists.txt b/test/llvm/CMakeLists.txt
index bc1ccc75..58f2249a 100644
--- a/test/llvm/CMakeLists.txt
+++ b/test/llvm/CMakeLists.txt
@@ -21,6 +21,7 @@ add_executable(
   llvmcodebuilder_test.cpp
   llvminstructionlist_test.cpp
   type_analyzer/variabletypechangesinloop_test.cpp
+  type_analyzer/variabletype_test.cpp
 )
 
 target_link_libraries(
diff --git a/test/llvm/type_analyzer/variabletype_test.cpp b/test/llvm/type_analyzer/variabletype_test.cpp
new file mode 100644
index 00000000..5b600e73
--- /dev/null
+++ b/test/llvm/type_analyzer/variabletype_test.cpp
@@ -0,0 +1,994 @@
+#include <scratchcpp/variable.h>
+#include <engine/internal/llvm/llvmtypeanalyzer.h>
+#include <engine/internal/llvm/llvmvariableptr.h>
+#include <engine/internal/llvm/llvminstruction.h>
+#include <engine/internal/llvm/llvminstructionlist.h>
+#include <engine/internal/llvm/llvmconstantregister.h>
+#include <gtest/gtest.h>
+
+using namespace libscratchcpp;
+
+TEST(LLVMTypeAnalyzer_VariableType, NullParams)
+{
+    LLVMTypeAnalyzer analyzer;
+    ASSERT_EQ(analyzer.variableType(nullptr, nullptr, Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, NullVariable)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.variableType(nullptr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, NullPos)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMVariablePtr varPtr;
+    ASSERT_EQ(analyzer.variableType(&varPtr, nullptr, Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, NoWriteOperationsKnownType)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, NoWriteOperationsUnknownType)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeNumber_Before)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 1.25);
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeNumber_After)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 1.25);
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeBool_Before)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Bool, true);
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Bool);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeBool_After)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Bool, true);
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Bool);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeString_Before)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeString_After)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteStringOptimization)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "1.25");
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    // Although string is assigned, it's constant and represents a number
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteMultipleVariables)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var1("", "");
+    Variable var2("", "");
+    varPtr.var = &var1;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    // Set var1
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 6);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Set var2
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    setVar2->workVariable = &var2;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteFromUnknownType_Before)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMRegister value(Compiler::StaticType::Unknown);
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteFromUnknownType_After)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMRegister value(Compiler::StaticType::Unknown);
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteToUnknownType_Before)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 5);
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    // The type is known because a number is assigned before the point
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteToUnknownType_After)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 5);
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    // The type is not known because a number is assigned after the point
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteUnknownToUnknownType_Before)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMRegister value(Compiler::StaticType::Unknown);
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteUnknownToUnknownType_After)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMRegister value(Compiler::StaticType::Unknown);
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeNumberToString_Before)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeNumberToString_After)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeStringToNumber_After)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 5.8);
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeNumberToBool_After)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Bool, true);
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeBoolToNumber_Before)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 1);
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeBoolToNumber_After)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 1);
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeBoolToString_After)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "abc");
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeStringToBool_Before)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Bool, false);
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Bool);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeStringToBool_After)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Bool, false);
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, WriteSameTypeInLoop)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 1.25);
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, WriteDifferentTypeInLoop)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    // Type is not known because the loop might not run at all
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, OverrideDifferentTypeBeforeLoop)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 1.25);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25);
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, OverrideUnknownTypeBeforeLoop)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 1.25);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25);
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesSameTypeNumber)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    // First write: string "abc" (incompatible with Number)
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "abc");
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Second write: number 5.25 (compatible with Number pre-loop type)
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 5.25);
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    // Should return Number type because final assignment writes a number
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesSameTypeString)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    // First write: number 42 (incompatible with String)
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Second write: string "hello" (compatible with String pre-loop type)
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "hello");
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    // Should return String type because final assignment writes a string
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesSameTypeUnknown)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    // First write: unknown type
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMRegister value1(Compiler::StaticType::Unknown);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Second write: string "hello" (compatible with String pre-loop type)
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "hello");
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    // Should return String type because final assignment writes a string
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesWithStringOptimization)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    // First write: string "abc" (incompatible with Number)
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "abc");
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Second write: string "3.14" (optimized to Number, compatible with pre-loop type)
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "3.14");
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    // Should return Number type because final assignment writes a string which is optimized to Number type
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesNumberToString)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    // First write: number 42 (compatible with Number)
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Second write: string "hello" (incompatible with Number pre-loop type)
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "hello");
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    // Should return String type because final assignment writes a string
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesBoolToNumber)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 42.5);
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    // Should return Number type because final assignment writes a number
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesBoolToString)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "hello");
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    // Should return String type because final assignment writes a string
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesBoolToStringNumberOptimization)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "3.14");
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    // String "3.14" gets optimized to Number, which is still different from Bool
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number);
+}
+
+// TODO: Handle cross-variable dependencies

From 2c2bf751faa847dcc3b17337bce355e55f5b1506 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Thu, 24 Jul 2025 16:35:44 +0200
Subject: [PATCH 23/79] LLVMTypeAnalyzer: Ignore unknown pre-loop type

---
 src/engine/internal/llvm/llvmtypeanalyzer.cpp            | 9 +++++----
 .../type_analyzer/variabletypechangesinloop_test.cpp     | 6 +-----
 2 files changed, 6 insertions(+), 9 deletions(-)

diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
index f0e4c749..dc9ecc18 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
@@ -56,9 +56,6 @@ bool LLVMTypeAnalyzer::variableTypeChangesInLoop(LLVMVariablePtr *varPtr, LLVMIn
     if (!varPtr || !loopBody)
         return false;
 
-    if (preLoopType == Compiler::StaticType::Unknown)
-        return true;
-
     // Find loop end
     LLVMInstruction *ins = loopBody->next;
     int loopLevel = 0;
@@ -180,5 +177,9 @@ bool LLVMTypeAnalyzer::typesMatch(LLVMInstruction *ins, Compiler::StaticType exp
     /*if (argIns && (argIns->type == LLVMInstruction::Type::ReadVariable || argIns->type == LLVMInstruction::Type::GetListItem))
         return isVarOrListTypeSafe(argIns.get(), expectedType, log, c);*/
 
-    return (writeValueType(ins) == expectedType);
+    if (expectedType == Compiler::StaticType::Unknown) {
+        // Equal unknown types are not considered a match
+        return false;
+    } else
+        return (writeValueType(ins) == expectedType);
 }
diff --git a/test/llvm/type_analyzer/variabletypechangesinloop_test.cpp b/test/llvm/type_analyzer/variabletypechangesinloop_test.cpp
index c5befa24..dd782f1d 100644
--- a/test/llvm/type_analyzer/variabletypechangesinloop_test.cpp
+++ b/test/llvm/type_analyzer/variabletypechangesinloop_test.cpp
@@ -65,8 +65,7 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, EmptyLoopUnknownType)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    // Always returns true for unknown type
-    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Unknown));
+    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Unknown));
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NoWriteOperations)
@@ -232,7 +231,6 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteFromUnknownType)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    // Always returns true for unknown type
     ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
@@ -256,7 +254,6 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteToUnknownType)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    // Always returns true for unknown type
     ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Unknown));
 }
 
@@ -280,7 +277,6 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteUnknownToUnknownType
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    // Always returns true for unknown type
     ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Unknown));
 }
 

From ee90056f834d8e51bef225839aaad0b05e80c905 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Fri, 25 Jul 2025 18:28:32 +0200
Subject: [PATCH 24/79] variableTypeChangesInLoop() ->
 variableTypeChangesInBranch()

---
 src/engine/internal/llvm/llvmtypeanalyzer.cpp |  90 ++-
 src/engine/internal/llvm/llvmtypeanalyzer.h   |   5 +-
 test/llvm/CMakeLists.txt                      |   2 +-
 ...p => variabletypechangesinbranch_test.cpp} | 707 +++++++++++++++---
 4 files changed, 670 insertions(+), 134 deletions(-)
 rename test/llvm/type_analyzer/{variabletypechangesinloop_test.cpp => variabletypechangesinbranch_test.cpp} (55%)

diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
index dc9ecc18..10b41959 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
@@ -40,7 +40,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(LLVMVariablePtr *varPtr, LLV
 
     if (loopStart) {
         // Analyze the first loop that was found
-        if (variableTypeChangesInLoop(varPtr, loopStart, previousType))
+        if (variableTypeChangesInBranch(varPtr, loopStart, previousType))
             return write ? writeValueType(write) : Compiler::StaticType::Unknown;
     } else if (write) {
         // There wasn't any loop found, so we can just check the last write operation
@@ -51,69 +51,60 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(LLVMVariablePtr *varPtr, LLV
     return previousType;
 }
 
-bool LLVMTypeAnalyzer::variableTypeChangesInLoop(LLVMVariablePtr *varPtr, LLVMInstruction *loopBody, Compiler::StaticType preLoopType) const
+bool LLVMTypeAnalyzer::variableTypeChangesInBranch(LLVMVariablePtr *varPtr, LLVMInstruction *start, Compiler::StaticType previousType) const
 {
-    if (!varPtr || !loopBody)
+    if (!varPtr || !start)
         return false;
 
-    // Find loop end
-    LLVMInstruction *ins = loopBody->next;
-    int loopLevel = 0;
+    assert(isLoopStart(start) || isIfStart(start) || isElse(start));
 
-    while (ins && !(isLoopEnd(ins) && loopLevel == 0)) {
-        if (isLoopStart(ins))
-            loopLevel++;
-        else if (isLoopEnd(ins)) {
-            assert(loopLevel > 0);
-            loopLevel--;
+    // Find loop/if statement end or else branch
+    LLVMInstruction *ins = start->next;
+    int level = 0;
+
+    while (ins && !((isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) && level == 0)) {
+        if (isLoopStart(ins) || isIfStart(ins))
+            level++;
+        else if (isLoopEnd(ins) || isIfEnd(ins)) {
+            assert(level > 0);
+            level--;
         }
 
         ins = ins->next;
     }
 
-    // Loops must always have an end instruction
     if (!ins) {
         assert(false);
         return true;
     }
 
-    return variableTypeChangesInLoopFromEnd(varPtr, ins, preLoopType);
+    // Process the branch from end
+    return variableTypeChangesInBranchFromEnd(varPtr, ins, previousType);
 }
 
-bool LLVMTypeAnalyzer::variableTypeChangesInLoopFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *loopEnd, Compiler::StaticType preLoopType) const
+bool LLVMTypeAnalyzer::variableTypeChangesInBranchFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *end, Compiler::StaticType previousType) const
 {
     // Find the last write instruction
-    LLVMInstruction *ins = loopEnd->previous;
+    LLVMInstruction *ins = end->previous;
 
-    while (ins && !isLoopStart(ins)) {
+    while (ins && !isLoopStart(ins) && !isIfStart(ins)) {
         if (isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) {
-            // Nested loop or if statement
-            if (variableTypeChangesInLoopFromEnd(varPtr, ins, preLoopType))
+            // Process the nested loop or if statement
+            if (variableTypeChangesInBranchFromEnd(varPtr, ins, previousType))
                 return true;
 
-            // Skip the loop or if statement
-            int level = 0;
-            ins = ins->previous;
-
-            while (ins && !((isLoopStart(ins) || isIfStart(ins) || isElse(ins)) && level == 0)) {
-                if (isLoopStart(ins) || isIfStart(ins)) {
-                    assert(level > 0);
-                    level--;
-                }
-
-                if (isLoopEnd(ins) || isIfEnd(ins) || isElse(ins))
-                    level++;
+            ins = skipBranch(ins);
 
-                ins = ins->previous;
-            };
+            if (isElse(ins)) {
+                // Process if branch (the else branch is already processed)
+                if (variableTypeChangesInBranchFromEnd(varPtr, ins, previousType))
+                    return true;
 
-            if (!ins) {
-                assert(false);
-                return true;
+                ins = skipBranch(ins);
             }
         } else if (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var) {
             // Variable write instruction
-            return !typesMatch(ins, preLoopType);
+            return !typesMatch(ins, previousType);
         }
 
         ins = ins->previous;
@@ -122,6 +113,31 @@ bool LLVMTypeAnalyzer::variableTypeChangesInLoopFromEnd(LLVMVariablePtr *varPtr,
     return false;
 }
 
+LLVMInstruction *LLVMTypeAnalyzer::skipBranch(LLVMInstruction *pos) const
+{
+    int level = 0;
+    pos = pos->previous;
+
+    while (pos && !((isLoopStart(pos) || isIfStart(pos)) && level == 0)) {
+        if (isLoopStart(pos) || isIfStart(pos)) {
+            assert(level > 0);
+            level--;
+        }
+
+        if (isLoopEnd(pos) || isIfEnd(pos) || isElse(pos)) {
+            if (isElse(pos) && level == 0)
+                break;
+
+            level++;
+        }
+
+        pos = pos->previous;
+    };
+
+    assert(pos);
+    return pos;
+}
+
 bool LLVMTypeAnalyzer::isLoopStart(LLVMInstruction *ins) const
 {
     return (BEGIN_LOOP_INSTRUCTIONS.find(ins->type) != BEGIN_LOOP_INSTRUCTIONS.cend());
diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.h b/src/engine/internal/llvm/llvmtypeanalyzer.h
index 86935282..9ba9c5ca 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.h
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.h
@@ -13,10 +13,11 @@ class LLVMTypeAnalyzer
 {
     public:
         Compiler::StaticType variableType(LLVMVariablePtr *varPtr, LLVMInstruction *pos, Compiler::StaticType previousType) const;
-        bool variableTypeChangesInLoop(LLVMVariablePtr *varPtr, LLVMInstruction *loopBody, Compiler::StaticType preLoopType) const;
+        bool variableTypeChangesInBranch(LLVMVariablePtr *varPtr, LLVMInstruction *start, Compiler::StaticType previousType) const;
 
     private:
-        bool variableTypeChangesInLoopFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *loopEnd, Compiler::StaticType preLoopType) const;
+        bool variableTypeChangesInBranchFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *end, Compiler::StaticType previousType) const;
+        LLVMInstruction *skipBranch(LLVMInstruction *pos) const;
         bool isLoopStart(LLVMInstruction *ins) const;
         bool isLoopEnd(LLVMInstruction *ins) const;
         bool isIfStart(LLVMInstruction *ins) const;
diff --git a/test/llvm/CMakeLists.txt b/test/llvm/CMakeLists.txt
index 58f2249a..70f7ecd9 100644
--- a/test/llvm/CMakeLists.txt
+++ b/test/llvm/CMakeLists.txt
@@ -20,7 +20,7 @@ add_executable(
   llvmexecutablecode_test.cpp
   llvmcodebuilder_test.cpp
   llvminstructionlist_test.cpp
-  type_analyzer/variabletypechangesinloop_test.cpp
+  type_analyzer/variabletypechangesinbranch_test.cpp
   type_analyzer/variabletype_test.cpp
 )
 
diff --git a/test/llvm/type_analyzer/variabletypechangesinloop_test.cpp b/test/llvm/type_analyzer/variabletypechangesinbranch_test.cpp
similarity index 55%
rename from test/llvm/type_analyzer/variabletypechangesinloop_test.cpp
rename to test/llvm/type_analyzer/variabletypechangesinbranch_test.cpp
index dd782f1d..329c84e3 100644
--- a/test/llvm/type_analyzer/variabletypechangesinloop_test.cpp
+++ b/test/llvm/type_analyzer/variabletypechangesinbranch_test.cpp
@@ -8,13 +8,13 @@
 
 using namespace libscratchcpp;
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NullParams)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NullParams)
 {
     LLVMTypeAnalyzer analyzer;
-    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(nullptr, nullptr, Compiler::StaticType::Number));
+    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(nullptr, nullptr, Compiler::StaticType::Number));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NullVariable)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NullVariable)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -28,17 +28,17 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NullVariable)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(nullptr, start.get(), Compiler::StaticType::Number));
+    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(nullptr, start.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NullLoopBody)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NullStartInstruction)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMVariablePtr varPtr;
-    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, nullptr, Compiler::StaticType::Number));
+    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, nullptr, Compiler::StaticType::Number));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, EmptyLoop)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, EmptyLoop)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMVariablePtr varPtr;
@@ -50,10 +50,61 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, EmptyLoop)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, EmptyLoopUnknownType)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, EmptyIfStatement)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMVariablePtr varPtr;
+    LLVMInstructionList list;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(start);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
+}
+
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, EmptyIfElseStatement_IfBranch)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMVariablePtr varPtr;
+    LLVMInstructionList list;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(start);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    list.addInstruction(elseStart);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
+}
+
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, EmptyIfElseStatement_ElseBranch)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMVariablePtr varPtr;
+    LLVMInstructionList list;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(start);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    list.addInstruction(elseStart);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, elseStart.get(), Compiler::StaticType::Number));
+}
+
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, EmptyLoopUnknownType)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMVariablePtr varPtr;
@@ -65,10 +116,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, EmptyLoopUnknownType)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Unknown));
+    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Unknown));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NoWriteOperations)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NoWriteOperations)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -83,10 +134,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NoWriteOperations)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteSameTypeNumber)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteSameTypeNumber)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -106,10 +157,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteSameTypeNumber)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteSameTypeBool)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteSameTypeBool)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -129,10 +180,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteSameTypeBool)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Bool));
+    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Bool));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteSameTypeString)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteSameTypeString)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -152,10 +203,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteSameTypeString)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::String));
+    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::String));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteStringOptimization)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteStringOptimization)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -176,10 +227,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteStringOptimization)
     list.addInstruction(end);
 
     // Although string is assigned, it's constant and represents a number
-    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteMultipleVariables)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteMultipleVariables)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -208,10 +259,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteMultipleVariables)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteFromUnknownType)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteFromUnknownType)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -231,10 +282,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteFromUnknownType)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteToUnknownType)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteToUnknownType)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -254,10 +305,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteToUnknownType)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Unknown));
+    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Unknown));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteUnknownToUnknownType)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteUnknownToUnknownType)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -277,10 +328,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteUnknownToUnknownType
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Unknown));
+    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Unknown));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeNumberToString)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeNumberToString)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -300,10 +351,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeNumberT
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeStringToNumber)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeStringToNumber)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -323,10 +374,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeStringT
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::String));
+    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::String));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeNumberToBool)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeNumberToBool)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -346,10 +397,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeNumberT
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeBoolToNumber)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeBoolToNumber)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -369,10 +420,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeBoolToN
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Bool));
+    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Bool));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeBoolToString)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeBoolToString)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -392,10 +443,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeBoolToS
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Bool));
+    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Bool));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeStringToBool)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeStringToBool)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -415,10 +466,56 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, SingleWriteDifferentTypeStringT
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::String));
+    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::String));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesSameTypeNumber)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteSameType_IfStatement)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(start);
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 1.25);
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
+}
+
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentType_IfStatement)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(start);
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 5.8);
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::String));
+}
+
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameTypeNumber)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -447,10 +544,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesSameTypeNumber)
     list.addInstruction(end);
 
     // Should return false because final assignment is compatible with pre-loop Number type
-    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesSameTypeString)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameTypeString)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -479,10 +576,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesSameTypeString)
     list.addInstruction(end);
 
     // Should return false because final assignment is compatible with pre-loop String type
-    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::String));
+    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::String));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesSameTypeUnknown)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameTypeUnknown)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -511,10 +608,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesSameTypeUnknown)
     list.addInstruction(end);
 
     // Should return false because final assignment is compatible with pre-loop String type
-    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::String));
+    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::String));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesWithStringOptimization)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesWithStringOptimization)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -543,10 +640,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesWithStringOptimiz
     list.addInstruction(end);
 
     // Should return false because final assignment is optimized to Number type
-    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesNumberToString)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesNumberToString)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -575,10 +672,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesNumberToString)
     list.addInstruction(end);
 
     // Should return true because final assignment is incompatible with pre-loop Number type
-    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesBoolToNumber)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesBoolToNumber)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -589,19 +686,27 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesBoolToNumber)
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
-    LLVMConstantRegister value(Compiler::StaticType::Number, 42.5);
-    setVar->workVariable = &var;
-    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
-    list.addInstruction(setVar);
+    // First write: compatible with Bool
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Bool, true);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Second write: number 4.25 (incompatible with Bool pre-loop type)
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, 4.25);
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
 
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Bool));
+    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Bool));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesBoolToString)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesBoolToString)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -612,19 +717,27 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesBoolToString)
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
-    LLVMConstantRegister value(Compiler::StaticType::String, "hello");
-    setVar->workVariable = &var;
-    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
-    list.addInstruction(setVar);
+    // First write: compatible with Bool
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Bool, true);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Second write: string "hello" (incompatible with Bool pre-loop type)
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "hello");
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
 
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Bool));
+    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Bool));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesBoolToStringNumberOptimization)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameType_IfStatement)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -632,23 +745,228 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleWritesBoolToStringNumbe
     Variable var("", "");
     varPtr.var = &var;
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
     list.addInstruction(start);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
-    LLVMConstantRegister value(Compiler::StaticType::String, "3.14");
-    setVar->workVariable = &var;
-    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
-    list.addInstruction(setVar);
+    // First write: string "abc" (incompatible with Number)
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "abc");
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    // Second write: number 5.25 (compatible with Number type)
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 5.25);
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(end);
+
+    // Should return false because final assignment is compatible with Number type
+    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
+}
+
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameType_IfBranch)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(start);
+
+    // First write: string "abc" (incompatible with Number)
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "abc");
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Second write: number 5.25 (compatible with Number type)
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 5.25);
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    list.addInstruction(elseStart);
+
+    // Else branch write: string "test" (incompatible with Number type)
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value3(Compiler::StaticType::String, "test");
+    setVar3->workVariable = &var;
+    setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    list.addInstruction(setVar3);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(end);
+
+    // Should return false because final assignment is compatible with Number type
+    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
+}
+
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameType_ElseBranch)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(start);
+
+    // First write: string "abc" (incompatible with Number)
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "abc");
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    list.addInstruction(elseStart);
+
+    // Else branch first write: string "abc" (incompatible with Number)
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "abc");
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    // Else branch second write: number 5.25 (compatible with Number type)
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value3(Compiler::StaticType::Number, 5.25);
+    setVar3->workVariable = &var;
+    setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    list.addInstruction(setVar3);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(end);
+
+    // Should return false because final assignment is compatible with Number type
+    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, elseStart.get(), Compiler::StaticType::Number));
+}
+
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesDifferentTypes_IfStatement)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(start);
+
+    // First write: compatible with Bool
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Bool, true);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Second write: string "hello" (incompatible with Bool type)
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "hello");
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
     list.addInstruction(end);
 
-    // String "3.14" gets optimized to Number, which is still different from Bool
-    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Bool));
+    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Bool));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, TypeChangeInIfBranch)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesDifferentTypes_IfBranch)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(start);
+
+    // First write: compatible with Bool
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Bool, true);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Second write: string "hello" (incompatible with Bool type)
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "hello");
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    list.addInstruction(elseStart);
+
+    // Else branch write: compatible with Bool
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value3(Compiler::StaticType::Bool, true);
+    setVar3->workVariable = &var;
+    setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    list.addInstruction(setVar3);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Bool));
+}
+
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesDifferentTypes_ElseBranch)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(start);
+
+    // First write: compatible with Bool
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Bool, true);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    list.addInstruction(elseStart);
+
+    // First else branch write: compatible with Bool
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Bool, true);
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    // Second else branch write: string "hello" (incompatible with Bool type)
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value3(Compiler::StaticType::String, "hello");
+    setVar3->workVariable = &var;
+    setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    list.addInstruction(setVar3);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, elseStart.get(), Compiler::StaticType::Bool));
+}
+
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, IfStatementInLoop_TypeChangeInIfBranch)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -686,10 +1004,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, TypeChangeInIfBranch)
     list.addInstruction(end);
 
     // Returns true because the type-changing branch might run
-    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, TypeChangeInElseBranch)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, IfStatementInLoop_TypeChangeInElseBranch)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -727,10 +1045,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, TypeChangeInElseBranch)
     list.addInstruction(end);
 
     // Returns true because the type-changing branch might run
-    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, IfElseWithoutTypeChange)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, IfStatementInLoop_IfElseWithoutTypeChange)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -767,10 +1085,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, IfElseWithoutTypeChange)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NestedLoopWithTypeChange)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NestedLoopWithTypeChange)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -808,10 +1126,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NestedLoopWithTypeChange)
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
+    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NestedLoopWithoutTypeChange)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NestedLoopWithoutTypeChange)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -849,10 +1167,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NestedLoopWithoutTypeChange)
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
+    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NestedLoopTypeChangesButResets)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NestedLoopTypeChangesButResets)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -897,10 +1215,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NestedLoopTypeChangesButResets)
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
+    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NestedLoopTypeChangesAndDoesNotReset)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NestedLoopTypeChangesAndDoesNotReset)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -945,10 +1263,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NestedLoopTypeChangesAndDoesNot
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
+    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NestedLoopWithTypeChangeBeforeLoop)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NestedLoopWithTypeChangeBeforeLoop)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -987,10 +1305,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, NestedLoopWithTypeChangeBeforeL
     list.addInstruction(outerEnd);
 
     // Returns true because loops can be skipped
-    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
+    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleNestedLoopsWithTypeChange)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleNestedLoopsWithTypeChange)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -1043,10 +1361,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleNestedLoopsWithTypeChan
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_TRUE(analyzer.variableTypeChangesInLoop(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
+    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleNestedLoopsWithTypeChangeButTypeReset)
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleNestedLoopsWithTypeChangeButTypeReset)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -1099,7 +1417,208 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInLoop, MultipleNestedLoopsWithTypeChan
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_FALSE(analyzer.variableTypeChangesInLoop(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
+    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
+}
+
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleNestedIfStatementsWithTypeChange_IfBranch)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    // Outer if statement begin
+    auto outerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(outerIf);
+
+    // Variable write inside outer if statement
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Inner if statement 1 begin
+    auto innerIf1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(innerIf1);
+
+    // Variable write inside inner if statement 1
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75);
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    // Inner if statement 2 begin
+    auto innerIf2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(innerIf2);
+
+    // Variable write inside inner if statement 2
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value3(Compiler::StaticType::String, "abc");
+    setVar3->workVariable = &var;
+    setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    list.addInstruction(setVar3);
+
+    // Inner if statement 2 else branch
+    auto innerElse2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    list.addInstruction(innerElse2);
+
+    // Variable write inside inner if statement 2 else branch
+    auto setVar4 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value4(Compiler::StaticType::Number, 4);
+    setVar4->workVariable = &var;
+    setVar4->args.push_back({ Compiler::StaticType::Unknown, &value4 });
+    list.addInstruction(setVar4);
+
+    // Inner if statement 2 end
+    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(innerEnd2);
+
+    // Inner if statement 1 end
+    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(innerEnd1);
+
+    // Outer if statement end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(outerEnd);
+
+    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, outerIf.get(), Compiler::StaticType::Number));
+}
+
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleNestedIfStatementsWithTypeChange_ElseBranch)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    // Outer if statement begin
+    auto outerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(outerIf);
+
+    // Variable write inside outer if statement
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Inner if statement 1 begin
+    auto innerIf1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(innerIf1);
+
+    // Variable write inside inner if statement 1
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75);
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    // Inner if statement 2 begin
+    auto innerIf2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(innerIf2);
+
+    // Variable write inside inner if statement 2
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value3(Compiler::StaticType::Number, 4);
+    setVar3->workVariable = &var;
+    setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    list.addInstruction(setVar3);
+
+    // Inner if statement 2 else branch
+    auto innerElse2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    list.addInstruction(innerElse2);
+
+    // Variable write inside inner if statement 2 else branch
+    auto setVar4 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value4(Compiler::StaticType::String, "abc");
+    setVar4->workVariable = &var;
+    setVar4->args.push_back({ Compiler::StaticType::Unknown, &value4 });
+    list.addInstruction(setVar4);
+
+    // Inner if statement 2 end
+    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(innerEnd2);
+
+    // Inner if statement 1 end
+    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(innerEnd1);
+
+    // Outer if statement end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(outerEnd);
+
+    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, outerIf.get(), Compiler::StaticType::Number));
+}
+
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleNestedIfStatementsWithoutTypeChange)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    // Outer if statement begin
+    auto outerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(outerIf);
+
+    // Variable write inside outer if statement
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Inner if statement 1 begin
+    auto innerIf1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(innerIf1);
+
+    // Variable write inside inner if statement 1
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75);
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    // Inner if statement 2 begin
+    auto innerIf2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(innerIf2);
+
+    // Variable write inside inner if statement 2
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value3(Compiler::StaticType::Number, 4);
+    setVar3->workVariable = &var;
+    setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    list.addInstruction(setVar3);
+
+    // Inner if statement 2 else branch
+    auto innerElse2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    list.addInstruction(innerElse2);
+
+    // Variable write inside inner if statement 2 else branch
+    auto setVar4 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value4(Compiler::StaticType::Number, 0);
+    setVar4->workVariable = &var;
+    setVar4->args.push_back({ Compiler::StaticType::Unknown, &value4 });
+    list.addInstruction(setVar4);
+
+    // Inner if statement 2 end
+    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(innerEnd2);
+
+    // Inner if statement 1 end
+    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(innerEnd1);
+
+    // Outer if statement end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(outerEnd);
+
+    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, outerIf.get(), Compiler::StaticType::Number));
 }
 
 // TODO: Handle cross-variable dependencies

From 6cddc410507d8969de7bc20099618c191e175929 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Fri, 25 Jul 2025 20:39:29 +0200
Subject: [PATCH 25/79] LLVMTypeAnalyzer: Handle all nested loop/if statement
 cases

---
 src/engine/internal/llvm/llvmtypeanalyzer.cpp | 113 ++-
 src/engine/internal/llvm/llvmtypeanalyzer.h   |   5 +-
 test/llvm/type_analyzer/variabletype_test.cpp | 775 ++++++++++++++++++
 3 files changed, 878 insertions(+), 15 deletions(-)

diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
index 10b41959..4da5290a 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
@@ -17,19 +17,23 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(LLVMVariablePtr *varPtr, LLV
     // Check the last write operation before the instruction
     LLVMInstruction *ins = pos;
     LLVMInstruction *write = nullptr;
-    LLVMInstruction *loopStart = nullptr;
+    LLVMInstruction *firstBranch = nullptr;
+    LLVMInstruction *firstElseBranch = nullptr;
     int level = 0;
 
     while (ins) {
-        if (isLoopEnd(ins))
+        if (isLoopEnd(ins) || isIfEnd(ins))
             level++;
-        else if (isLoopStart(ins)) {
+        else if (isLoopStart(ins) || isIfStart(ins)) {
             level--;
-
-            if (!loopStart)
-                loopStart = ins;
+            firstBranch = ins;
+        } else if (isElse(ins)) {
+            // Skip if branch if coming from else
+            firstElseBranch = ins;
+            ins = skipBranch(ins);
+            continue;
         } else if (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var) {
-            if (level <= 0) { // ignore nested loops (they're handled later)
+            if (level <= 0) { // ignore nested branches (they're handled by the branch analyzer)
                 write = ins;
                 break;
             }
@@ -38,12 +42,20 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(LLVMVariablePtr *varPtr, LLV
         ins = ins->previous;
     }
 
-    if (loopStart) {
-        // Analyze the first loop that was found
-        if (variableTypeChangesInBranch(varPtr, loopStart, previousType))
-            return write ? writeValueType(write) : Compiler::StaticType::Unknown;
+    if (firstBranch) {
+        // Analyze the first branch and else branch
+        if (write)
+            previousType = writeValueType(write); // write operation overrides previous type
+
+        Compiler::StaticType firstBranchType = variableTypeAfterBranch(varPtr, firstBranch, previousType);
+        Compiler::StaticType elseBranchType = variableTypeAfterBranch(varPtr, firstElseBranch, previousType);
+
+        if (typesMatch(firstBranchType, elseBranchType))
+            return firstBranchType;
+        else
+            return Compiler::StaticType::Unknown;
     } else if (write) {
-        // There wasn't any loop found, so we can just check the last write operation
+        // There wasn't any branch found, so we can just check the last write operation
         return writeValueType(write);
     }
 
@@ -82,6 +94,72 @@ bool LLVMTypeAnalyzer::variableTypeChangesInBranch(LLVMVariablePtr *varPtr, LLVM
     return variableTypeChangesInBranchFromEnd(varPtr, ins, previousType);
 }
 
+Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(LLVMVariablePtr *varPtr, LLVMInstruction *start, Compiler::StaticType previousType) const
+{
+    if (!varPtr || !start)
+        return previousType;
+
+    assert(isLoopStart(start) || isIfStart(start) || isElse(start));
+
+    // Find loop/if statement end or else branch
+    LLVMInstruction *ins = start->next;
+    int level = 0;
+
+    while (ins && !((isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) && level == 0)) {
+        if (isLoopStart(ins) || isIfStart(ins))
+            level++;
+        else if (isLoopEnd(ins) || isIfEnd(ins)) {
+            assert(level > 0);
+            level--;
+        }
+
+        ins = ins->next;
+    }
+
+    if (!ins) {
+        assert(false);
+        return Compiler::StaticType::Unknown;
+    }
+
+    // Process the branch from end
+    return variableTypeAfterBranchFromEnd(varPtr, ins, previousType);
+}
+
+Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *end, Compiler::StaticType previousType) const
+{
+    // Find the last write instruction
+    LLVMInstruction *ins = end->previous;
+
+    while (ins && !isLoopStart(ins) && !isIfStart(ins)) {
+        if (isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) {
+            // Process the nested loop or if statement
+            Compiler::StaticType ret = variableTypeAfterBranchFromEnd(varPtr, ins, previousType);
+
+            if (!typesMatch(ret, previousType))
+                return ret;
+
+            ins = skipBranch(ins);
+
+            if (isElse(ins)) {
+                // Process if branch (the else branch is already processed)
+                ret = variableTypeAfterBranchFromEnd(varPtr, ins, previousType);
+
+                if (!typesMatch(ret, previousType))
+                    return ret;
+
+                ins = skipBranch(ins);
+            }
+        } else if (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var) {
+            // Variable write instruction
+            return writeValueType(ins);
+        }
+
+        ins = ins->previous;
+    }
+
+    return previousType;
+}
+
 bool LLVMTypeAnalyzer::variableTypeChangesInBranchFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *end, Compiler::StaticType previousType) const
 {
     // Find the last write instruction
@@ -104,7 +182,7 @@ bool LLVMTypeAnalyzer::variableTypeChangesInBranchFromEnd(LLVMVariablePtr *varPt
             }
         } else if (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var) {
             // Variable write instruction
-            return !typesMatch(ins, previousType);
+            return !writeTypesMatch(ins, previousType);
         }
 
         ins = ins->previous;
@@ -185,7 +263,13 @@ Compiler::StaticType LLVMTypeAnalyzer::writeValueType(LLVMInstruction *ins) cons
     return optimizeRegisterType(arg);
 }
 
-bool LLVMTypeAnalyzer::typesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const
+bool LLVMTypeAnalyzer::typesMatch(Compiler::StaticType a, Compiler::StaticType b) const
+{
+    // Equal unknown types are not considered a match
+    return (a == b) && (a != Compiler::StaticType::Unknown);
+}
+
+bool LLVMTypeAnalyzer::writeTypesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const
 {
     // auto argIns = arg->instruction;
 
@@ -193,6 +277,7 @@ bool LLVMTypeAnalyzer::typesMatch(LLVMInstruction *ins, Compiler::StaticType exp
     /*if (argIns && (argIns->type == LLVMInstruction::Type::ReadVariable || argIns->type == LLVMInstruction::Type::GetListItem))
         return isVarOrListTypeSafe(argIns.get(), expectedType, log, c);*/
 
+    return typesMatch(writeValueType(ins), expectedType);
     if (expectedType == Compiler::StaticType::Unknown) {
         // Equal unknown types are not considered a match
         return false;
diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.h b/src/engine/internal/llvm/llvmtypeanalyzer.h
index 9ba9c5ca..c91d6d42 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.h
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.h
@@ -16,6 +16,8 @@ class LLVMTypeAnalyzer
         bool variableTypeChangesInBranch(LLVMVariablePtr *varPtr, LLVMInstruction *start, Compiler::StaticType previousType) const;
 
     private:
+        Compiler::StaticType variableTypeAfterBranch(LLVMVariablePtr *varPtr, LLVMInstruction *start, Compiler::StaticType previousType) const;
+        Compiler::StaticType variableTypeAfterBranchFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *end, Compiler::StaticType previousType) const;
         bool variableTypeChangesInBranchFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *end, Compiler::StaticType previousType) const;
         LLVMInstruction *skipBranch(LLVMInstruction *pos) const;
         bool isLoopStart(LLVMInstruction *ins) const;
@@ -26,7 +28,8 @@ class LLVMTypeAnalyzer
 
         Compiler::StaticType optimizeRegisterType(LLVMRegister *reg) const;
         Compiler::StaticType writeValueType(LLVMInstruction *ins) const;
-        bool typesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const;
+        bool typesMatch(Compiler::StaticType a, Compiler::StaticType b) const;
+        bool writeTypesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const;
 };
 
 } // namespace libscratchcpp
diff --git a/test/llvm/type_analyzer/variabletype_test.cpp b/test/llvm/type_analyzer/variabletype_test.cpp
index 5b600e73..82e7ceef 100644
--- a/test/llvm/type_analyzer/variabletype_test.cpp
+++ b/test/llvm/type_analyzer/variabletype_test.cpp
@@ -783,6 +783,141 @@ TEST(LLVMTypeAnalyzer_VariableType, OverrideUnknownTypeBeforeLoop)
     ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Number);
 }
 
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, WriteSameTypeInIfStatement)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(start);
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 1.25);
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, WriteDifferentTypeInIfStatement)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(start);
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 5.8);
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    // Type is not known because the if statement might not run at all
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, OverrideDifferentTypeBeforeIfElseStatement)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 1.25);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(start);
+
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25);
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    list.addInstruction(elseStart);
+
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value3(Compiler::StaticType::Number, 2.5);
+    setVar3->workVariable = &var;
+    setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    list.addInstruction(setVar3);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, OverrideUnknownTypeBeforeIfElseStatement)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 1.25);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(start);
+
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25);
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    list.addInstruction(elseStart);
+
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value3(Compiler::StaticType::Number, 2.5);
+    setVar3->workVariable = &var;
+    setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    list.addInstruction(setVar3);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Number);
+}
+
 TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesSameTypeNumber)
 {
     LLVMTypeAnalyzer analyzer;
@@ -991,4 +1126,644 @@ TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesBoolToStringNumberOptimization
     ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number);
 }
 
+TEST(LLVMTypeAnalyzer_VariableType, TypeChangeInIfBranch)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(ifStart);
+
+    // First write - changes type
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "test");
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    list.addInstruction(elseStart);
+
+    // Second write - does not change type
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 42);
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(ifEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    // Returns unknown type because both branches might run
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, TypeChangeInElseBranch)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(ifStart);
+
+    // First write - does not change type
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    list.addInstruction(elseStart);
+
+    // Second write - changes type
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(ifEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    // Returns unknown type because both branches might run
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, IfElseWithEqualTypes_SameType)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(ifStart);
+
+    // First write - does not change type
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    list.addInstruction(elseStart);
+
+    // Second write - does not change type
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25);
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(ifEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, IfElseWithEqualTypes_DifferentTypes)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(ifStart);
+
+    // First write - changes type to string
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "Lorem");
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    list.addInstruction(elseStart);
+
+    // Second write - changes type to string
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "ipsum");
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(ifEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithTypeChange_Before)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(outerLoop);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    // Variable write inside outer loop
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Inner loop begin
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(innerLoop);
+
+    // Variable write inside inner loop
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    // Inner loop end
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(innerEnd);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(outerEnd);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithTypeChange_BeforeInner)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(outerLoop);
+
+    // Variable write inside outer loop
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    // Inner loop begin
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(innerLoop);
+
+    // Variable write inside inner loop
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    // Inner loop end
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(innerEnd);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(outerEnd);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithTypeChange_AfterWriteInsideInner)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(outerLoop);
+
+    // Variable write inside outer loop
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Inner loop begin
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(innerLoop);
+
+    // Variable write inside inner loop
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    // Inner loop end
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(innerEnd);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(outerEnd);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithTypeChange_After)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(outerLoop);
+
+    // Variable write inside outer loop
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Inner loop begin
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(innerLoop);
+
+    // Variable write inside inner loop
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    // Inner loop end
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(innerEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(outerEnd);
+
+    // Type is not known because the inner loop might not run at all
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithoutTypeChange)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginWhileLoop, nullptr, false);
+    list.addInstruction(outerLoop);
+
+    // Variable write inside outer loop
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Inner loop begin
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(innerLoop);
+
+    // Variable write inside inner loop
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 2.5);
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    // Inner loop end
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(innerEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(outerEnd);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, NestedLoopTypeChangesButResets)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(outerLoop);
+
+    // Variable write inside outer loop
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Inner loop begin
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false);
+    list.addInstruction(innerLoop);
+
+    // Variable write inside inner loop
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    // Inner loop end
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(innerEnd);
+
+    // Variable write after inner loop - resets type
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value3(Compiler::StaticType::Number, 2);
+    setVar3->workVariable = &var;
+    setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    list.addInstruction(setVar3);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(outerEnd);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, NestedLoopTypeChangesAndDoesNotReset)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(outerLoop);
+
+    // Variable write inside outer loop
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Inner loop begin
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginWhileLoop, nullptr, false);
+    list.addInstruction(innerLoop);
+
+    // Variable write inside inner loop
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    // Inner loop end
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(innerEnd);
+
+    // Variable write after inner loop - keeps the different type
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value3(Compiler::StaticType::String, "abc");
+    setVar3->workVariable = &var;
+    setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    list.addInstruction(setVar3);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(outerEnd);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, MultipleNestedLoopsWithTypeChange)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(outerLoop);
+
+    // Variable write inside outer loop
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Inner loop 1 begin
+    auto innerLoop1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(innerLoop1);
+
+    // Variable write inside inner loop 1
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75);
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    // Inner loop 2 begin
+    auto innerLoop2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(innerLoop2);
+
+    // Variable write inside inner loop 2
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value3(Compiler::StaticType::String, "abc");
+    setVar3->workVariable = &var;
+    setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    list.addInstruction(setVar3);
+
+    // Inner loop 2 end
+    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(innerEnd2);
+
+    // Inner loop 1 end
+    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(innerEnd1);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(outerEnd);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, MultipleNestedLoopsWithTypeChangeButTypeReset)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(outerLoop);
+
+    // Variable write inside outer loop
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Inner loop 1 begin
+    auto innerLoop1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(innerLoop1);
+
+    // Inner loop 2 begin
+    auto innerLoop2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(innerLoop2);
+
+    // Variable write inside inner loop 2
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "abc");
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    // Inner loop 2 end
+    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(innerEnd2);
+
+    // Variable write inside inner loop 1 - resets type
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value3(Compiler::StaticType::Number, 2.75);
+    setVar3->workVariable = &var;
+    setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    list.addInstruction(setVar3);
+
+    // Inner loop 1 end
+    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(innerEnd1);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(outerEnd);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, SameTypeIfElseInLoopWithTypeChange)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(outerLoop);
+
+    // Inner if statement begin
+    auto innerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(innerIf);
+
+    // Variable write inside inner if statement if branch
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "abc");
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Inner if statement else branch
+    auto innerElse = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    list.addInstruction(innerElse);
+
+    // Variable write inside inner if statement else branch
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "def");
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    // Inner if statement end
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(innerEnd);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(outerEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    // The type always changes to string
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
+}
+
 // TODO: Handle cross-variable dependencies

From 41b04d85b4c2a92ea336b2842c868a3f1e4f13b7 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Fri, 25 Jul 2025 22:49:14 +0200
Subject: [PATCH 26/79] LLVMTypeAnalyzer: Drop variableTypeChangesInBranch()

variableTypeAfterBranch() is the preferred method now
---
 src/engine/internal/llvm/llvmtypeanalyzer.cpp |  82 ++-----
 src/engine/internal/llvm/llvmtypeanalyzer.h   |   4 +-
 test/llvm/CMakeLists.txt                      |   2 +-
 test/llvm/type_analyzer/variabletype_test.cpp |   2 +-
 ...t.cpp => variabletypeafterbranch_test.cpp} | 210 +++++++++---------
 5 files changed, 123 insertions(+), 177 deletions(-)
 rename test/llvm/type_analyzer/{variabletypechangesinbranch_test.cpp => variabletypeafterbranch_test.cpp} (84%)

diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
index 4da5290a..284fa7a3 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
@@ -63,37 +63,6 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(LLVMVariablePtr *varPtr, LLV
     return previousType;
 }
 
-bool LLVMTypeAnalyzer::variableTypeChangesInBranch(LLVMVariablePtr *varPtr, LLVMInstruction *start, Compiler::StaticType previousType) const
-{
-    if (!varPtr || !start)
-        return false;
-
-    assert(isLoopStart(start) || isIfStart(start) || isElse(start));
-
-    // Find loop/if statement end or else branch
-    LLVMInstruction *ins = start->next;
-    int level = 0;
-
-    while (ins && !((isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) && level == 0)) {
-        if (isLoopStart(ins) || isIfStart(ins))
-            level++;
-        else if (isLoopEnd(ins) || isIfEnd(ins)) {
-            assert(level > 0);
-            level--;
-        }
-
-        ins = ins->next;
-    }
-
-    if (!ins) {
-        assert(false);
-        return true;
-    }
-
-    // Process the branch from end
-    return variableTypeChangesInBranchFromEnd(varPtr, ins, previousType);
-}
-
 Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(LLVMVariablePtr *varPtr, LLVMInstruction *start, Compiler::StaticType previousType) const
 {
     if (!varPtr || !start)
@@ -129,14 +98,17 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(LLVMVariab
 {
     // Find the last write instruction
     LLVMInstruction *ins = end->previous;
+    bool typeMightReset = false;
 
     while (ins && !isLoopStart(ins) && !isIfStart(ins)) {
         if (isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) {
             // Process the nested loop or if statement
             Compiler::StaticType ret = variableTypeAfterBranchFromEnd(varPtr, ins, previousType);
 
-            if (!typesMatch(ret, previousType))
-                return ret;
+            if (typesMatch(ret, previousType))
+                typeMightReset = true;
+            else
+                return Compiler::StaticType::Unknown;
 
             ins = skipBranch(ins);
 
@@ -144,51 +116,27 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(LLVMVariab
                 // Process if branch (the else branch is already processed)
                 ret = variableTypeAfterBranchFromEnd(varPtr, ins, previousType);
 
-                if (!typesMatch(ret, previousType))
-                    return ret;
+                if (typesMatch(ret, previousType))
+                    typeMightReset = true;
+                else
+                    return Compiler::StaticType::Unknown;
 
                 ins = skipBranch(ins);
             }
         } else if (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var) {
             // Variable write instruction
-            return writeValueType(ins);
-        }
-
-        ins = ins->previous;
-    }
-
-    return previousType;
-}
-
-bool LLVMTypeAnalyzer::variableTypeChangesInBranchFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *end, Compiler::StaticType previousType) const
-{
-    // Find the last write instruction
-    LLVMInstruction *ins = end->previous;
-
-    while (ins && !isLoopStart(ins) && !isIfStart(ins)) {
-        if (isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) {
-            // Process the nested loop or if statement
-            if (variableTypeChangesInBranchFromEnd(varPtr, ins, previousType))
-                return true;
+            Compiler::StaticType writeType = writeValueType(ins);
 
-            ins = skipBranch(ins);
-
-            if (isElse(ins)) {
-                // Process if branch (the else branch is already processed)
-                if (variableTypeChangesInBranchFromEnd(varPtr, ins, previousType))
-                    return true;
-
-                ins = skipBranch(ins);
-            }
-        } else if (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var) {
-            // Variable write instruction
-            return !writeTypesMatch(ins, previousType);
+            if (typesMatch(writeType, previousType))
+                return writeType;
+            else
+                return typeMightReset ? Compiler::StaticType::Unknown : writeType;
         }
 
         ins = ins->previous;
     }
 
-    return false;
+    return previousType;
 }
 
 LLVMInstruction *LLVMTypeAnalyzer::skipBranch(LLVMInstruction *pos) const
diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.h b/src/engine/internal/llvm/llvmtypeanalyzer.h
index c91d6d42..ee29cc0d 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.h
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.h
@@ -13,12 +13,10 @@ class LLVMTypeAnalyzer
 {
     public:
         Compiler::StaticType variableType(LLVMVariablePtr *varPtr, LLVMInstruction *pos, Compiler::StaticType previousType) const;
-        bool variableTypeChangesInBranch(LLVMVariablePtr *varPtr, LLVMInstruction *start, Compiler::StaticType previousType) const;
+        Compiler::StaticType variableTypeAfterBranch(LLVMVariablePtr *varPtr, LLVMInstruction *start, Compiler::StaticType previousType) const;
 
     private:
-        Compiler::StaticType variableTypeAfterBranch(LLVMVariablePtr *varPtr, LLVMInstruction *start, Compiler::StaticType previousType) const;
         Compiler::StaticType variableTypeAfterBranchFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *end, Compiler::StaticType previousType) const;
-        bool variableTypeChangesInBranchFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *end, Compiler::StaticType previousType) const;
         LLVMInstruction *skipBranch(LLVMInstruction *pos) const;
         bool isLoopStart(LLVMInstruction *ins) const;
         bool isLoopEnd(LLVMInstruction *ins) const;
diff --git a/test/llvm/CMakeLists.txt b/test/llvm/CMakeLists.txt
index 70f7ecd9..0ba3385a 100644
--- a/test/llvm/CMakeLists.txt
+++ b/test/llvm/CMakeLists.txt
@@ -20,7 +20,7 @@ add_executable(
   llvmexecutablecode_test.cpp
   llvmcodebuilder_test.cpp
   llvminstructionlist_test.cpp
-  type_analyzer/variabletypechangesinbranch_test.cpp
+  type_analyzer/variabletypeafterbranch_test.cpp
   type_analyzer/variabletype_test.cpp
 )
 
diff --git a/test/llvm/type_analyzer/variabletype_test.cpp b/test/llvm/type_analyzer/variabletype_test.cpp
index 82e7ceef..992d54f5 100644
--- a/test/llvm/type_analyzer/variabletype_test.cpp
+++ b/test/llvm/type_analyzer/variabletype_test.cpp
@@ -1763,7 +1763,7 @@ TEST(LLVMTypeAnalyzer_VariableType, SameTypeIfElseInLoopWithTypeChange)
     list.addInstruction(funcCall);
 
     // The type always changes to string
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
 }
 
 // TODO: Handle cross-variable dependencies
diff --git a/test/llvm/type_analyzer/variabletypechangesinbranch_test.cpp b/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp
similarity index 84%
rename from test/llvm/type_analyzer/variabletypechangesinbranch_test.cpp
rename to test/llvm/type_analyzer/variabletypeafterbranch_test.cpp
index 329c84e3..334becb8 100644
--- a/test/llvm/type_analyzer/variabletypechangesinbranch_test.cpp
+++ b/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp
@@ -8,13 +8,13 @@
 
 using namespace libscratchcpp;
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NullParams)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NullParams)
 {
     LLVMTypeAnalyzer analyzer;
-    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(nullptr, nullptr, Compiler::StaticType::Number));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(nullptr, nullptr, Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NullVariable)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NullVariable)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -28,17 +28,17 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NullVariable)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(nullptr, start.get(), Compiler::StaticType::Number));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(nullptr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NullStartInstruction)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NullStartInstruction)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMVariablePtr varPtr;
-    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, nullptr, Compiler::StaticType::Number));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, nullptr, Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, EmptyLoop)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyLoop)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMVariablePtr varPtr;
@@ -50,10 +50,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, EmptyLoop)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, EmptyIfStatement)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyIfStatement)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMVariablePtr varPtr;
@@ -65,10 +65,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, EmptyIfStatement)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, EmptyIfElseStatement_IfBranch)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyIfElseStatement_IfBranch)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMVariablePtr varPtr;
@@ -83,10 +83,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, EmptyIfElseStatement_IfBranch
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, EmptyIfElseStatement_ElseBranch)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyIfElseStatement_ElseBranch)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMVariablePtr varPtr;
@@ -101,10 +101,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, EmptyIfElseStatement_ElseBran
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, elseStart.get(), Compiler::StaticType::Number));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, elseStart.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, EmptyLoopUnknownType)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyLoopUnknownType)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMVariablePtr varPtr;
@@ -116,10 +116,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, EmptyLoopUnknownType)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Unknown));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NoWriteOperations)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NoWriteOperations)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -134,10 +134,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NoWriteOperations)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteSameTypeNumber)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteSameTypeNumber)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -157,10 +157,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteSameTypeNumber)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteSameTypeBool)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteSameTypeBool)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -180,10 +180,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteSameTypeBool)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Bool));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::Bool);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteSameTypeString)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteSameTypeString)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -203,10 +203,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteSameTypeString)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::String));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::String), Compiler::StaticType::String);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteStringOptimization)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteStringOptimization)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -227,10 +227,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteStringOptimization
     list.addInstruction(end);
 
     // Although string is assigned, it's constant and represents a number
-    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteMultipleVariables)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteMultipleVariables)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -259,10 +259,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteMultipleVariables)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteFromUnknownType)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteFromUnknownType)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -282,10 +282,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteFromUnknownType)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteToUnknownType)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteToUnknownType)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -305,10 +305,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteToUnknownType)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Unknown));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Number);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteUnknownToUnknownType)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteUnknownToUnknownType)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -328,10 +328,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteUnknownToUnknownTy
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Unknown));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeNumberToString)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeNumberToString)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -351,10 +351,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeNumbe
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeStringToNumber)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeStringToNumber)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -374,10 +374,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeStrin
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::String));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::String), Compiler::StaticType::Number);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeNumberToBool)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeNumberToBool)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -397,10 +397,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeNumbe
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Bool);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeBoolToNumber)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeBoolToNumber)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -420,10 +420,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeBoolT
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Bool));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeBoolToString)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeBoolToString)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -443,10 +443,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeBoolT
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Bool));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::String);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeStringToBool)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeStringToBool)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -466,10 +466,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentTypeStrin
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::String));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::String), Compiler::StaticType::Bool);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteSameType_IfStatement)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteSameType_IfStatement)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -489,10 +489,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteSameType_IfStateme
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentType_IfStatement)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentType_IfStatement)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -512,10 +512,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, SingleWriteDifferentType_IfSt
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::String));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::String), Compiler::StaticType::Number);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameTypeNumber)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameTypeNumber)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -544,10 +544,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameTypeNumber)
     list.addInstruction(end);
 
     // Should return false because final assignment is compatible with pre-loop Number type
-    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameTypeString)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameTypeString)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -576,10 +576,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameTypeString)
     list.addInstruction(end);
 
     // Should return false because final assignment is compatible with pre-loop String type
-    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::String));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::String), Compiler::StaticType::String);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameTypeUnknown)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameTypeUnknown)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -608,10 +608,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameTypeUnknown
     list.addInstruction(end);
 
     // Should return false because final assignment is compatible with pre-loop String type
-    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::String));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::String), Compiler::StaticType::String);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesWithStringOptimization)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesWithStringOptimization)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -640,10 +640,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesWithStringOptim
     list.addInstruction(end);
 
     // Should return false because final assignment is optimized to Number type
-    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesNumberToString)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesNumberToString)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -672,10 +672,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesNumberToString)
     list.addInstruction(end);
 
     // Should return true because final assignment is incompatible with pre-loop Number type
-    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesBoolToNumber)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesBoolToNumber)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -703,10 +703,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesBoolToNumber)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Bool));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesBoolToString)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesBoolToString)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -734,10 +734,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesBoolToString)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Bool));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::String);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameType_IfStatement)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameType_IfStatement)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -766,10 +766,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameType_IfStat
     list.addInstruction(end);
 
     // Should return false because final assignment is compatible with Number type
-    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameType_IfBranch)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameType_IfBranch)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -808,10 +808,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameType_IfBran
     list.addInstruction(end);
 
     // Should return false because final assignment is compatible with Number type
-    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameType_ElseBranch)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameType_ElseBranch)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -850,10 +850,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesSameType_ElseBr
     list.addInstruction(end);
 
     // Should return false because final assignment is compatible with Number type
-    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, elseStart.get(), Compiler::StaticType::Number));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, elseStart.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesDifferentTypes_IfStatement)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesDifferentTypes_IfStatement)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -881,10 +881,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesDifferentTypes_
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Bool));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::String);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesDifferentTypes_IfBranch)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesDifferentTypes_IfBranch)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -922,10 +922,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesDifferentTypes_
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Bool));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::String);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesDifferentTypes_ElseBranch)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesDifferentTypes_ElseBranch)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -963,10 +963,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleWritesDifferentTypes_
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, elseStart.get(), Compiler::StaticType::Bool));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, elseStart.get(), Compiler::StaticType::Bool), Compiler::StaticType::String);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, IfStatementInLoop_TypeChangeInIfBranch)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoop_TypeChangeInIfBranch)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -1003,11 +1003,11 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, IfStatementInLoop_TypeChangeI
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    // Returns true because the type-changing branch might run
-    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
+    // Returns unknown type because the type-changing branch might or might not run
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, IfStatementInLoop_TypeChangeInElseBranch)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoop_TypeChangeInElseBranch)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -1044,11 +1044,11 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, IfStatementInLoop_TypeChangeI
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    // Returns true because the type-changing branch might run
-    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
+    // Returns unknown type because the type-changing branch might or might not run
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, IfStatementInLoop_IfElseWithoutTypeChange)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoop_IfElseWithoutTypeChange)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -1085,10 +1085,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, IfStatementInLoop_IfElseWitho
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, start.get(), Compiler::StaticType::Number));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NestedLoopWithTypeChange)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopWithTypeChange)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -1126,10 +1126,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NestedLoopWithTypeChange)
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NestedLoopWithoutTypeChange)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopWithoutTypeChange)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -1167,10 +1167,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NestedLoopWithoutTypeChange)
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NestedLoopTypeChangesButResets)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopTypeChangesButResets)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -1215,10 +1215,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NestedLoopTypeChangesButReset
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NestedLoopTypeChangesAndDoesNotReset)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopTypeChangesAndDoesNotReset)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -1263,10 +1263,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NestedLoopTypeChangesAndDoesN
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NestedLoopWithTypeChangeBeforeLoop)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopWithTypeChangeBeforeLoop)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -1304,11 +1304,11 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, NestedLoopWithTypeChangeBefor
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(outerEnd);
 
-    // Returns true because loops can be skipped
-    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
+    // Returns unknown type because loops can be skipped
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleNestedLoopsWithTypeChange)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedLoopsWithTypeChange)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -1361,10 +1361,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleNestedLoopsWithTypeCh
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleNestedLoopsWithTypeChangeButTypeReset)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedLoopsWithTypeChangeButTypeReset)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -1417,10 +1417,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleNestedLoopsWithTypeCh
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleNestedIfStatementsWithTypeChange_IfBranch)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedIfStatementsWithTypeChange_IfBranch)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -1484,10 +1484,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleNestedIfStatementsWit
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, outerIf.get(), Compiler::StaticType::Number));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerIf.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleNestedIfStatementsWithTypeChange_ElseBranch)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedIfStatementsWithTypeChange_ElseBranch)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -1551,10 +1551,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleNestedIfStatementsWit
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_TRUE(analyzer.variableTypeChangesInBranch(&varPtr, outerIf.get(), Compiler::StaticType::Number));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerIf.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleNestedIfStatementsWithoutTypeChange)
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedIfStatementsWithoutTypeChange)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -1618,7 +1618,7 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, MultipleNestedIfStatementsWit
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_FALSE(analyzer.variableTypeChangesInBranch(&varPtr, outerIf.get(), Compiler::StaticType::Number));
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerIf.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 // TODO: Handle cross-variable dependencies

From bcf26d7f888bc94acf717ba6314e97f7d9c23781 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Fri, 25 Jul 2025 22:50:44 +0200
Subject: [PATCH 27/79] LLVMTypeAnalyzer: Fix type mismatch in
 MultipleWritesBoolToNumber test

---
 test/llvm/type_analyzer/variabletypeafterbranch_test.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp b/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp
index 334becb8..4bde29c4 100644
--- a/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp
+++ b/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp
@@ -695,7 +695,7 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesBoolToNumber)
 
     // Second write: number 4.25 (incompatible with Bool pre-loop type)
     auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
-    LLVMConstantRegister value2(Compiler::StaticType::String, 4.25);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 4.25);
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);

From 8698a95406f8f74b55d6b13d007fe6f23e548931 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Fri, 25 Jul 2025 23:35:45 +0200
Subject: [PATCH 28/79] LLVMTypeAnalyzer: Support more edge cases

---
 src/engine/internal/llvm/llvmtypeanalyzer.cpp |  29 ++--
 src/engine/internal/llvm/llvmtypeanalyzer.h   |   2 +-
 .../variabletypeafterbranch_test.cpp          | 144 ++++++++++++++++++
 3 files changed, 164 insertions(+), 11 deletions(-)

diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
index 284fa7a3..d59577a5 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
@@ -91,10 +91,11 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(LLVMVariablePtr *
     }
 
     // Process the branch from end
-    return variableTypeAfterBranchFromEnd(varPtr, ins, previousType);
+    bool write = false; // only used internally (the compiler doesn't need this)
+    return variableTypeAfterBranchFromEnd(varPtr, ins, previousType, write);
 }
 
-Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *end, Compiler::StaticType previousType) const
+Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *end, Compiler::StaticType previousType, bool &write) const
 {
     // Find the last write instruction
     LLVMInstruction *ins = end->previous;
@@ -103,22 +104,28 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(LLVMVariab
     while (ins && !isLoopStart(ins) && !isIfStart(ins)) {
         if (isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) {
             // Process the nested loop or if statement
-            Compiler::StaticType ret = variableTypeAfterBranchFromEnd(varPtr, ins, previousType);
+            Compiler::StaticType ret = variableTypeAfterBranchFromEnd(varPtr, ins, previousType, write);
 
-            if (typesMatch(ret, previousType))
-                typeMightReset = true;
-            else
+            if (typesMatch(ret, previousType)) {
+                if (write)
+                    typeMightReset = true;
+            } else
                 return Compiler::StaticType::Unknown;
 
             ins = skipBranch(ins);
 
             if (isElse(ins)) {
                 // Process if branch (the else branch is already processed)
-                ret = variableTypeAfterBranchFromEnd(varPtr, ins, previousType);
+                ret = variableTypeAfterBranchFromEnd(varPtr, ins, previousType, write);
 
-                if (typesMatch(ret, previousType))
-                    typeMightReset = true;
-                else
+                if (typesMatch(ret, previousType)) {
+                    if (write) {
+                        if (typeMightReset)
+                            return previousType;
+
+                        typeMightReset = true;
+                    }
+                } else
                     return Compiler::StaticType::Unknown;
 
                 ins = skipBranch(ins);
@@ -126,6 +133,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(LLVMVariab
         } else if (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var) {
             // Variable write instruction
             Compiler::StaticType writeType = writeValueType(ins);
+            write = true;
 
             if (typesMatch(writeType, previousType))
                 return writeType;
@@ -136,6 +144,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(LLVMVariab
         ins = ins->previous;
     }
 
+    write = false;
     return previousType;
 }
 
diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.h b/src/engine/internal/llvm/llvmtypeanalyzer.h
index ee29cc0d..a8376a36 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.h
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.h
@@ -16,7 +16,7 @@ class LLVMTypeAnalyzer
         Compiler::StaticType variableTypeAfterBranch(LLVMVariablePtr *varPtr, LLVMInstruction *start, Compiler::StaticType previousType) const;
 
     private:
-        Compiler::StaticType variableTypeAfterBranchFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *end, Compiler::StaticType previousType) const;
+        Compiler::StaticType variableTypeAfterBranchFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *end, Compiler::StaticType previousType, bool &write) const;
         LLVMInstruction *skipBranch(LLVMInstruction *pos) const;
         bool isLoopStart(LLVMInstruction *ins) const;
         bool isLoopEnd(LLVMInstruction *ins) const;
diff --git a/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp b/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp
index 4bde29c4..8fcf5fc0 100644
--- a/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp
+++ b/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp
@@ -1308,6 +1308,150 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopWithTypeChangeBeforeLoo
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
 }
 
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoopWithTypeChangeBeforeLoop_TypeChangeInIfBranch)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false);
+    list.addInstruction(outerLoop);
+
+    // Variable write inside outer loop
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "test");
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Inner if statement begin
+    auto innerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(innerIf);
+
+    // Variable write inside inner if statement if branch
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 5);
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    // Inner if statement else branch begin
+    auto innerElse = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    list.addInstruction(innerElse);
+
+    // Inner if statement end
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(innerEnd);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(outerEnd);
+
+    // Returns unknown type because if statements can be skipped
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoopWithTypeChangeBeforeLoop_TypeChangeInElseBranch)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false);
+    list.addInstruction(outerLoop);
+
+    // Variable write inside outer loop
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "test");
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Inner if statement begin
+    auto innerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(innerIf);
+
+    // Inner if statement else branch begin
+    auto innerElse = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    list.addInstruction(innerElse);
+
+    // Variable write inside inner if statement else branch
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 5);
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    // Inner if statement end
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(innerEnd);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(outerEnd);
+
+    // Returns unknown type because if statements can be skipped
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoopWithTypeChangeBeforeLoop_TypeChangeInBothBranches)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false);
+    list.addInstruction(outerLoop);
+
+    // Variable write inside outer loop
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "test");
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Inner if statement begin
+    auto innerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(innerIf);
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 5);
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    // Inner if statement else branch begin
+    auto innerElse = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    list.addInstruction(innerElse);
+
+    // Variable write inside inner if statement else branch
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 5);
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    // Inner if statement end
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(innerEnd);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(outerEnd);
+
+    // Returns number type because the type always changes to number
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+}
+
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedLoopsWithTypeChange)
 {
     LLVMTypeAnalyzer analyzer;

From 54400ded319fbd811ca07dc60aedd2f9d1b71f9f Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Fri, 25 Jul 2025 23:38:09 +0200
Subject: [PATCH 29/79] LLVMTypeAnalyzer: Remove leftover dead code

---
 src/engine/internal/llvm/llvmtypeanalyzer.cpp | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
index d59577a5..c217ada5 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
@@ -235,9 +235,4 @@ bool LLVMTypeAnalyzer::writeTypesMatch(LLVMInstruction *ins, Compiler::StaticTyp
         return isVarOrListTypeSafe(argIns.get(), expectedType, log, c);*/
 
     return typesMatch(writeValueType(ins), expectedType);
-    if (expectedType == Compiler::StaticType::Unknown) {
-        // Equal unknown types are not considered a match
-        return false;
-    } else
-        return (writeValueType(ins) == expectedType);
 }

From 5b94db0aa790c24d284af46ad3cd01f6e4600bf0 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Sat, 26 Jul 2025 11:15:02 +0200
Subject: [PATCH 30/79] LLVMTypeAnalyzer: Fix some test case names

---
 test/llvm/type_analyzer/variabletype_test.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/test/llvm/type_analyzer/variabletype_test.cpp b/test/llvm/type_analyzer/variabletype_test.cpp
index 992d54f5..15a85287 100644
--- a/test/llvm/type_analyzer/variabletype_test.cpp
+++ b/test/llvm/type_analyzer/variabletype_test.cpp
@@ -783,7 +783,7 @@ TEST(LLVMTypeAnalyzer_VariableType, OverrideUnknownTypeBeforeLoop)
     ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Number);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, WriteSameTypeInIfStatement)
+TEST(LLVMTypeAnalyzer_VariableType, WriteSameTypeInIfStatement)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
@@ -809,7 +809,7 @@ TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, WriteSameTypeInIfStatement)
     ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
-TEST(LLVMTypeAnalyzer_VariableTypeChangesInBranch, WriteDifferentTypeInIfStatement)
+TEST(LLVMTypeAnalyzer_VariableType, WriteDifferentTypeInIfStatement)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;

From ea7c9b7a08cc3bf94f655a03937281f3411d6dfe Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Sat, 26 Jul 2025 11:16:52 +0200
Subject: [PATCH 31/79] LLVMTypeAnalyzer: Ignore writes after pos in if
 statements

---
 src/engine/internal/llvm/llvmtypeanalyzer.cpp |  15 ++-
 test/llvm/type_analyzer/variabletype_test.cpp | 115 ++++++++++++++++++
 2 files changed, 128 insertions(+), 2 deletions(-)

diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
index c217ada5..d960d7f2 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
@@ -19,12 +19,16 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(LLVMVariablePtr *varPtr, LLV
     LLVMInstruction *write = nullptr;
     LLVMInstruction *firstBranch = nullptr;
     LLVMInstruction *firstElseBranch = nullptr;
+    LLVMInstruction *ourBranch = nullptr;
     int level = 0;
 
     while (ins) {
         if (isLoopEnd(ins) || isIfEnd(ins))
             level++;
         else if (isLoopStart(ins) || isIfStart(ins)) {
+            if (!ourBranch && level == 0)
+                ourBranch = ins;
+
             level--;
             firstBranch = ins;
         } else if (isElse(ins)) {
@@ -44,11 +48,18 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(LLVMVariablePtr *varPtr, LLV
 
     if (firstBranch) {
         // Analyze the first branch and else branch
+        bool ignoreWriteAfterPos = (isIfStart(firstBranch) && firstBranch == ourBranch);
+
         if (write)
             previousType = writeValueType(write); // write operation overrides previous type
 
-        Compiler::StaticType firstBranchType = variableTypeAfterBranch(varPtr, firstBranch, previousType);
-        Compiler::StaticType elseBranchType = variableTypeAfterBranch(varPtr, firstElseBranch, previousType);
+        Compiler::StaticType firstBranchType = previousType;
+        Compiler::StaticType elseBranchType = previousType;
+
+        if (!ignoreWriteAfterPos) {
+            firstBranchType = variableTypeAfterBranch(varPtr, firstBranch, previousType);
+            elseBranchType = variableTypeAfterBranch(varPtr, firstElseBranch, previousType);
+        }
 
         if (typesMatch(firstBranchType, elseBranchType))
             return firstBranchType;
diff --git a/test/llvm/type_analyzer/variabletype_test.cpp b/test/llvm/type_analyzer/variabletype_test.cpp
index 15a85287..fbb837ed 100644
--- a/test/llvm/type_analyzer/variabletype_test.cpp
+++ b/test/llvm/type_analyzer/variabletype_test.cpp
@@ -666,6 +666,121 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeStringToBool_Af
     ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Unknown);
 }
 
+TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentType_BeforeAndAfter)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "test");
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Bool, true);
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, IfStatement_SingleWriteDifferentType_Before)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(start);
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, IfStatement_SingleWriteDifferentType_After_IfBranch)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(start);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(end);
+
+    // Since this isn't a loop, the write after the point doesn't affect the type
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, IfStatement_SingleWriteDifferentType_After_ElseBranch)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    LLVMVariablePtr varPtr;
+    Variable var("", "");
+    varPtr.var = &var;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(start);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    list.addInstruction(elseStart);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(end);
+
+    // Since this isn't a loop, the write after the point doesn't affect the type
+    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+}
+
 TEST(LLVMTypeAnalyzer_VariableType, WriteSameTypeInLoop)
 {
     LLVMTypeAnalyzer analyzer;

From ad367dc6ab7ca5d5a23e420cc0b4eb6ee7aee742 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Sat, 26 Jul 2025 11:21:48 +0200
Subject: [PATCH 32/79] LLVMTypeAnalyzer: Use isVariableWrite() to check
 variable writes

---
 src/engine/internal/llvm/llvmtypeanalyzer.cpp | 9 +++++++--
 src/engine/internal/llvm/llvmtypeanalyzer.h   | 1 +
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
index d960d7f2..a636f26c 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
@@ -36,7 +36,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(LLVMVariablePtr *varPtr, LLV
             firstElseBranch = ins;
             ins = skipBranch(ins);
             continue;
-        } else if (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var) {
+        } else if (isVariableWrite(ins, varPtr)) {
             if (level <= 0) { // ignore nested branches (they're handled by the branch analyzer)
                 write = ins;
                 break;
@@ -141,7 +141,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(LLVMVariab
 
                 ins = skipBranch(ins);
             }
-        } else if (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var) {
+        } else if (isVariableWrite(ins, varPtr)) {
             // Variable write instruction
             Compiler::StaticType writeType = writeValueType(ins);
             write = true;
@@ -209,6 +209,11 @@ bool LLVMTypeAnalyzer::isIfEnd(LLVMInstruction *ins) const
     return (ins->type == LLVMInstruction::Type::EndIf);
 }
 
+bool LLVMTypeAnalyzer::isVariableWrite(LLVMInstruction *ins, LLVMVariablePtr *varPtr) const
+{
+    return (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var);
+}
+
 Compiler::StaticType LLVMTypeAnalyzer::optimizeRegisterType(LLVMRegister *reg) const
 {
     // TODO: Move this method out if it's used in LLVMCodeBuilder too
diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.h b/src/engine/internal/llvm/llvmtypeanalyzer.h
index a8376a36..0af4e3ff 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.h
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.h
@@ -23,6 +23,7 @@ class LLVMTypeAnalyzer
         bool isIfStart(LLVMInstruction *ins) const;
         bool isElse(LLVMInstruction *ins) const;
         bool isIfEnd(LLVMInstruction *ins) const;
+        bool isVariableWrite(LLVMInstruction *ins, LLVMVariablePtr *varPtr) const;
 
         Compiler::StaticType optimizeRegisterType(LLVMRegister *reg) const;
         Compiler::StaticType writeValueType(LLVMInstruction *ins) const;

From 3f4d19feee161b5453dcb7dee111170dcc5d8dee Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Sat, 26 Jul 2025 11:50:40 +0200
Subject: [PATCH 33/79] LLVMTypeAnalyzer: Use Variable instead of
 LLVMVariablePtr

---
 src/engine/internal/llvm/llvmtypeanalyzer.cpp |  29 +--
 src/engine/internal/llvm/llvmtypeanalyzer.h   |   9 +-
 test/llvm/type_analyzer/variabletype_test.cpp | 241 +++++-------------
 .../variabletypeafterbranch_test.cpp          | 209 +++++----------
 4 files changed, 140 insertions(+), 348 deletions(-)

diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
index a636f26c..fa295e6b 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
@@ -2,16 +2,15 @@
 
 #include "llvmtypeanalyzer.h"
 #include "llvminstruction.h"
-#include "llvmvariableptr.h"
 
 using namespace libscratchcpp;
 
 static const std::unordered_set<LLVMInstruction::Type>
     BEGIN_LOOP_INSTRUCTIONS = { LLVMInstruction::Type::BeginRepeatLoop, LLVMInstruction::Type::BeginWhileLoop, LLVMInstruction::Type::BeginRepeatUntilLoop };
 
-Compiler::StaticType LLVMTypeAnalyzer::variableType(LLVMVariablePtr *varPtr, LLVMInstruction *pos, Compiler::StaticType previousType) const
+Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType) const
 {
-    if (!varPtr || !pos)
+    if (!var || !pos)
         return Compiler::StaticType::Unknown;
 
     // Check the last write operation before the instruction
@@ -36,7 +35,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(LLVMVariablePtr *varPtr, LLV
             firstElseBranch = ins;
             ins = skipBranch(ins);
             continue;
-        } else if (isVariableWrite(ins, varPtr)) {
+        } else if (isVariableWrite(ins, var)) {
             if (level <= 0) { // ignore nested branches (they're handled by the branch analyzer)
                 write = ins;
                 break;
@@ -57,8 +56,8 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(LLVMVariablePtr *varPtr, LLV
         Compiler::StaticType elseBranchType = previousType;
 
         if (!ignoreWriteAfterPos) {
-            firstBranchType = variableTypeAfterBranch(varPtr, firstBranch, previousType);
-            elseBranchType = variableTypeAfterBranch(varPtr, firstElseBranch, previousType);
+            firstBranchType = variableTypeAfterBranch(var, firstBranch, previousType);
+            elseBranchType = variableTypeAfterBranch(var, firstElseBranch, previousType);
         }
 
         if (typesMatch(firstBranchType, elseBranchType))
@@ -74,9 +73,9 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(LLVMVariablePtr *varPtr, LLV
     return previousType;
 }
 
-Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(LLVMVariablePtr *varPtr, LLVMInstruction *start, Compiler::StaticType previousType) const
+Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType) const
 {
-    if (!varPtr || !start)
+    if (!var || !start)
         return previousType;
 
     assert(isLoopStart(start) || isIfStart(start) || isElse(start));
@@ -103,10 +102,10 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(LLVMVariablePtr *
 
     // Process the branch from end
     bool write = false; // only used internally (the compiler doesn't need this)
-    return variableTypeAfterBranchFromEnd(varPtr, ins, previousType, write);
+    return variableTypeAfterBranchFromEnd(var, ins, previousType, write);
 }
 
-Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *end, Compiler::StaticType previousType, bool &write) const
+Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable *var, LLVMInstruction *end, Compiler::StaticType previousType, bool &write) const
 {
     // Find the last write instruction
     LLVMInstruction *ins = end->previous;
@@ -115,7 +114,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(LLVMVariab
     while (ins && !isLoopStart(ins) && !isIfStart(ins)) {
         if (isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) {
             // Process the nested loop or if statement
-            Compiler::StaticType ret = variableTypeAfterBranchFromEnd(varPtr, ins, previousType, write);
+            Compiler::StaticType ret = variableTypeAfterBranchFromEnd(var, ins, previousType, write);
 
             if (typesMatch(ret, previousType)) {
                 if (write)
@@ -127,7 +126,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(LLVMVariab
 
             if (isElse(ins)) {
                 // Process if branch (the else branch is already processed)
-                ret = variableTypeAfterBranchFromEnd(varPtr, ins, previousType, write);
+                ret = variableTypeAfterBranchFromEnd(var, ins, previousType, write);
 
                 if (typesMatch(ret, previousType)) {
                     if (write) {
@@ -141,7 +140,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(LLVMVariab
 
                 ins = skipBranch(ins);
             }
-        } else if (isVariableWrite(ins, varPtr)) {
+        } else if (isVariableWrite(ins, var)) {
             // Variable write instruction
             Compiler::StaticType writeType = writeValueType(ins);
             write = true;
@@ -209,9 +208,9 @@ bool LLVMTypeAnalyzer::isIfEnd(LLVMInstruction *ins) const
     return (ins->type == LLVMInstruction::Type::EndIf);
 }
 
-bool LLVMTypeAnalyzer::isVariableWrite(LLVMInstruction *ins, LLVMVariablePtr *varPtr) const
+bool LLVMTypeAnalyzer::isVariableWrite(LLVMInstruction *ins, Variable *var) const
 {
-    return (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == varPtr->var);
+    return (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == var);
 }
 
 Compiler::StaticType LLVMTypeAnalyzer::optimizeRegisterType(LLVMRegister *reg) const
diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.h b/src/engine/internal/llvm/llvmtypeanalyzer.h
index 0af4e3ff..3cb4cc4e 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.h
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.h
@@ -5,25 +5,24 @@
 namespace libscratchcpp
 {
 
-struct LLVMVariablePtr;
 struct LLVMInstruction;
 struct LLVMRegister;
 
 class LLVMTypeAnalyzer
 {
     public:
-        Compiler::StaticType variableType(LLVMVariablePtr *varPtr, LLVMInstruction *pos, Compiler::StaticType previousType) const;
-        Compiler::StaticType variableTypeAfterBranch(LLVMVariablePtr *varPtr, LLVMInstruction *start, Compiler::StaticType previousType) const;
+        Compiler::StaticType variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType) const;
+        Compiler::StaticType variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType) const;
 
     private:
-        Compiler::StaticType variableTypeAfterBranchFromEnd(LLVMVariablePtr *varPtr, LLVMInstruction *end, Compiler::StaticType previousType, bool &write) const;
+        Compiler::StaticType variableTypeAfterBranchFromEnd(Variable *var, LLVMInstruction *end, Compiler::StaticType previousType, bool &write) const;
         LLVMInstruction *skipBranch(LLVMInstruction *pos) const;
         bool isLoopStart(LLVMInstruction *ins) const;
         bool isLoopEnd(LLVMInstruction *ins) const;
         bool isIfStart(LLVMInstruction *ins) const;
         bool isElse(LLVMInstruction *ins) const;
         bool isIfEnd(LLVMInstruction *ins) const;
-        bool isVariableWrite(LLVMInstruction *ins, LLVMVariablePtr *varPtr) const;
+        bool isVariableWrite(LLVMInstruction *ins, Variable *var) const;
 
         Compiler::StaticType optimizeRegisterType(LLVMRegister *reg) const;
         Compiler::StaticType writeValueType(LLVMInstruction *ins) const;
diff --git a/test/llvm/type_analyzer/variabletype_test.cpp b/test/llvm/type_analyzer/variabletype_test.cpp
index fbb837ed..65037f60 100644
--- a/test/llvm/type_analyzer/variabletype_test.cpp
+++ b/test/llvm/type_analyzer/variabletype_test.cpp
@@ -1,6 +1,5 @@
 #include <scratchcpp/variable.h>
 #include <engine/internal/llvm/llvmtypeanalyzer.h>
-#include <engine/internal/llvm/llvmvariableptr.h>
 #include <engine/internal/llvm/llvminstruction.h>
 #include <engine/internal/llvm/llvminstructionlist.h>
 #include <engine/internal/llvm/llvmconstantregister.h>
@@ -28,41 +27,39 @@ TEST(LLVMTypeAnalyzer_VariableType, NullVariable)
 TEST(LLVMTypeAnalyzer_VariableType, NullPos)
 {
     LLVMTypeAnalyzer analyzer;
-    LLVMVariablePtr varPtr;
-    ASSERT_EQ(analyzer.variableType(&varPtr, nullptr, Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+    Variable var("", "");
+    ASSERT_EQ(analyzer.variableType(&var, nullptr, Compiler::StaticType::Number), Compiler::StaticType::Unknown);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, NoWriteOperationsKnownType)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
+    Variable var("", "");
 
     auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
     list.addInstruction(funcCall);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, NoWriteOperationsUnknownType)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
+    Variable var("", "");
 
     auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
     list.addInstruction(funcCall);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeNumber_Before)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -79,16 +76,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeNumber_Before)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeNumber_After)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -105,16 +100,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeNumber_After)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeBool_Before)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -131,16 +124,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeBool_Before)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Bool);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Bool);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeBool_After)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -157,16 +148,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeBool_After)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Bool);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Bool);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeString_Before)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -183,16 +172,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeString_Before)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::String);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::String);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeString_After)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -209,16 +196,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeString_After)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::String);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::String);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteStringOptimization)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -236,17 +221,15 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteStringOptimization)
     list.addInstruction(end);
 
     // Although string is assigned, it's constant and represents a number
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteMultipleVariables)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var1("", "");
     Variable var2("", "");
-    varPtr.var = &var1;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -271,16 +254,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteMultipleVariables)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableType(&var1, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteFromUnknownType_Before)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -297,16 +278,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteFromUnknownType_Before)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteFromUnknownType_After)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -323,16 +302,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteFromUnknownType_After)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteToUnknownType_Before)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -350,16 +327,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteToUnknownType_Before)
     list.addInstruction(end);
 
     // The type is known because a number is assigned before the point
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteToUnknownType_After)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -377,16 +352,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteToUnknownType_After)
     list.addInstruction(end);
 
     // The type is not known because a number is assigned after the point
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteUnknownToUnknownType_Before)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -403,16 +376,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteUnknownToUnknownType_Before)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteUnknownToUnknownType_After)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -429,16 +400,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteUnknownToUnknownType_After)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeNumberToString_Before)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -455,16 +424,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeNumberToString_
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeNumberToString_After)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -481,16 +448,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeNumberToString_
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeStringToNumber_After)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -507,16 +472,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeStringToNumber_
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Unknown);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Unknown);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeNumberToBool_After)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -533,16 +496,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeNumberToBool_Af
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeBoolToNumber_Before)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -559,16 +520,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeBoolToNumber_Be
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeBoolToNumber_After)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -585,16 +544,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeBoolToNumber_Af
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Unknown);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Unknown);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeBoolToString_After)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -611,16 +568,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeBoolToString_Af
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Unknown);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Unknown);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeStringToBool_Before)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -637,16 +592,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeStringToBool_Be
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Bool);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Bool);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeStringToBool_After)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -663,16 +616,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeStringToBool_Af
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Unknown);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Unknown);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentType_BeforeAndAfter)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -695,16 +646,14 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentType_BeforeAndAfter
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, IfStatement_SingleWriteDifferentType_Before)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
     list.addInstruction(start);
@@ -721,16 +670,14 @@ TEST(LLVMTypeAnalyzer_VariableType, IfStatement_SingleWriteDifferentType_Before)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, IfStatement_SingleWriteDifferentType_After_IfBranch)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
     list.addInstruction(start);
@@ -748,16 +695,14 @@ TEST(LLVMTypeAnalyzer_VariableType, IfStatement_SingleWriteDifferentType_After_I
     list.addInstruction(end);
 
     // Since this isn't a loop, the write after the point doesn't affect the type
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, IfStatement_SingleWriteDifferentType_After_ElseBranch)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
     list.addInstruction(start);
@@ -778,16 +723,14 @@ TEST(LLVMTypeAnalyzer_VariableType, IfStatement_SingleWriteDifferentType_After_E
     list.addInstruction(end);
 
     // Since this isn't a loop, the write after the point doesn't affect the type
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, WriteSameTypeInLoop)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -804,16 +747,14 @@ TEST(LLVMTypeAnalyzer_VariableType, WriteSameTypeInLoop)
     auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
     list.addInstruction(funcCall);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, WriteDifferentTypeInLoop)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -831,16 +772,14 @@ TEST(LLVMTypeAnalyzer_VariableType, WriteDifferentTypeInLoop)
     list.addInstruction(funcCall);
 
     // Type is not known because the loop might not run at all
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, OverrideDifferentTypeBeforeLoop)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 1.25);
@@ -863,16 +802,14 @@ TEST(LLVMTypeAnalyzer_VariableType, OverrideDifferentTypeBeforeLoop)
     auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
     list.addInstruction(funcCall);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, OverrideUnknownTypeBeforeLoop)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 1.25);
@@ -895,16 +832,14 @@ TEST(LLVMTypeAnalyzer_VariableType, OverrideUnknownTypeBeforeLoop)
     auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
     list.addInstruction(funcCall);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, WriteSameTypeInIfStatement)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
     list.addInstruction(start);
@@ -921,16 +856,14 @@ TEST(LLVMTypeAnalyzer_VariableType, WriteSameTypeInIfStatement)
     auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
     list.addInstruction(funcCall);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, WriteDifferentTypeInIfStatement)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
     list.addInstruction(start);
@@ -948,16 +881,14 @@ TEST(LLVMTypeAnalyzer_VariableType, WriteDifferentTypeInIfStatement)
     list.addInstruction(funcCall);
 
     // Type is not known because the if statement might not run at all
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Unknown);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Unknown);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, OverrideDifferentTypeBeforeIfElseStatement)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 1.25);
@@ -989,16 +920,14 @@ TEST(LLVMTypeAnalyzer_VariableType, OverrideDifferentTypeBeforeIfElseStatement)
     auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
     list.addInstruction(funcCall);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, OverrideUnknownTypeBeforeIfElseStatement)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 1.25);
@@ -1030,16 +959,14 @@ TEST(LLVMTypeAnalyzer_VariableType, OverrideUnknownTypeBeforeIfElseStatement)
     auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
     list.addInstruction(funcCall);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesSameTypeNumber)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     // First write: string "abc" (incompatible with Number)
     auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
@@ -1059,16 +986,14 @@ TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesSameTypeNumber)
     list.addInstruction(funcCall);
 
     // Should return Number type because final assignment writes a number
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesSameTypeString)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     // First write: number 42 (incompatible with String)
     auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
@@ -1088,16 +1013,14 @@ TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesSameTypeString)
     list.addInstruction(funcCall);
 
     // Should return String type because final assignment writes a string
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::String);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::String);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesSameTypeUnknown)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     // First write: unknown type
     auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
@@ -1117,16 +1040,14 @@ TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesSameTypeUnknown)
     list.addInstruction(funcCall);
 
     // Should return String type because final assignment writes a string
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::String);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::String);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesWithStringOptimization)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     // First write: string "abc" (incompatible with Number)
     auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
@@ -1146,16 +1067,14 @@ TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesWithStringOptimization)
     list.addInstruction(funcCall);
 
     // Should return Number type because final assignment writes a string which is optimized to Number type
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesNumberToString)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     // First write: number 42 (compatible with Number)
     auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
@@ -1175,16 +1094,14 @@ TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesNumberToString)
     list.addInstruction(funcCall);
 
     // Should return String type because final assignment writes a string
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesBoolToNumber)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 42.5);
@@ -1196,16 +1113,14 @@ TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesBoolToNumber)
     list.addInstruction(funcCall);
 
     // Should return Number type because final assignment writes a number
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesBoolToString)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "hello");
@@ -1217,16 +1132,14 @@ TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesBoolToString)
     list.addInstruction(funcCall);
 
     // Should return String type because final assignment writes a string
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::String);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::String);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesBoolToStringNumberOptimization)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "3.14");
@@ -1238,16 +1151,14 @@ TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesBoolToStringNumberOptimization
     list.addInstruction(funcCall);
 
     // String "3.14" gets optimized to Number, which is still different from Bool
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, TypeChangeInIfBranch)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
     list.addInstruction(ifStart);
@@ -1276,16 +1187,14 @@ TEST(LLVMTypeAnalyzer_VariableType, TypeChangeInIfBranch)
     list.addInstruction(funcCall);
 
     // Returns unknown type because both branches might run
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, TypeChangeInElseBranch)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
     list.addInstruction(ifStart);
@@ -1314,16 +1223,14 @@ TEST(LLVMTypeAnalyzer_VariableType, TypeChangeInElseBranch)
     list.addInstruction(funcCall);
 
     // Returns unknown type because both branches might run
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, IfElseWithEqualTypes_SameType)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
     list.addInstruction(ifStart);
@@ -1351,16 +1258,14 @@ TEST(LLVMTypeAnalyzer_VariableType, IfElseWithEqualTypes_SameType)
     auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
     list.addInstruction(funcCall);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, IfElseWithEqualTypes_DifferentTypes)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
     list.addInstruction(ifStart);
@@ -1388,16 +1293,14 @@ TEST(LLVMTypeAnalyzer_VariableType, IfElseWithEqualTypes_DifferentTypes)
     auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
     list.addInstruction(funcCall);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithTypeChange_Before)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     // Outer loop begin
     auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
@@ -1432,16 +1335,14 @@ TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithTypeChange_Before)
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithTypeChange_BeforeInner)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     // Outer loop begin
     auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
@@ -1476,16 +1377,14 @@ TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithTypeChange_BeforeInner)
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithTypeChange_AfterWriteInsideInner)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     // Outer loop begin
     auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
@@ -1520,16 +1419,14 @@ TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithTypeChange_AfterWriteInsideInn
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithTypeChange_After)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     // Outer loop begin
     auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
@@ -1565,16 +1462,14 @@ TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithTypeChange_After)
     list.addInstruction(outerEnd);
 
     // Type is not known because the inner loop might not run at all
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithoutTypeChange)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     // Outer loop begin
     auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginWhileLoop, nullptr, false);
@@ -1609,16 +1504,14 @@ TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithoutTypeChange)
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, NestedLoopTypeChangesButResets)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     // Outer loop begin
     auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
@@ -1660,16 +1553,14 @@ TEST(LLVMTypeAnalyzer_VariableType, NestedLoopTypeChangesButResets)
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, NestedLoopTypeChangesAndDoesNotReset)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     // Outer loop begin
     auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
@@ -1711,16 +1602,14 @@ TEST(LLVMTypeAnalyzer_VariableType, NestedLoopTypeChangesAndDoesNotReset)
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, MultipleNestedLoopsWithTypeChange)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     // Outer loop begin
     auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
@@ -1770,16 +1659,14 @@ TEST(LLVMTypeAnalyzer_VariableType, MultipleNestedLoopsWithTypeChange)
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, MultipleNestedLoopsWithTypeChangeButTypeReset)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     // Outer loop begin
     auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
@@ -1829,16 +1716,14 @@ TEST(LLVMTypeAnalyzer_VariableType, MultipleNestedLoopsWithTypeChangeButTypeRese
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableType, SameTypeIfElseInLoopWithTypeChange)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     // Outer loop begin
     auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
@@ -1878,7 +1763,7 @@ TEST(LLVMTypeAnalyzer_VariableType, SameTypeIfElseInLoopWithTypeChange)
     list.addInstruction(funcCall);
 
     // The type always changes to string
-    ASSERT_EQ(analyzer.variableType(&varPtr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
 }
 
 // TODO: Handle cross-variable dependencies
diff --git a/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp b/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp
index 8fcf5fc0..dc3db515 100644
--- a/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp
+++ b/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp
@@ -1,6 +1,5 @@
 #include <scratchcpp/variable.h>
 #include <engine/internal/llvm/llvmtypeanalyzer.h>
-#include <engine/internal/llvm/llvmvariableptr.h>
 #include <engine/internal/llvm/llvminstruction.h>
 #include <engine/internal/llvm/llvminstructionlist.h>
 #include <engine/internal/llvm/llvmconstantregister.h>
@@ -34,14 +33,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NullVariable)
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NullStartInstruction)
 {
     LLVMTypeAnalyzer analyzer;
-    LLVMVariablePtr varPtr;
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, nullptr, Compiler::StaticType::Number), Compiler::StaticType::Number);
+    Variable var("", "");
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, nullptr, Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyLoop)
 {
     LLVMTypeAnalyzer analyzer;
-    LLVMVariablePtr varPtr;
+    Variable var("", "");
     LLVMInstructionList list;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
@@ -50,13 +49,13 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyLoop)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyIfStatement)
 {
     LLVMTypeAnalyzer analyzer;
-    LLVMVariablePtr varPtr;
+    Variable var("", "");
     LLVMInstructionList list;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
@@ -65,13 +64,13 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyIfStatement)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyIfElseStatement_IfBranch)
 {
     LLVMTypeAnalyzer analyzer;
-    LLVMVariablePtr varPtr;
+    Variable var("", "");
     LLVMInstructionList list;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
@@ -83,13 +82,13 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyIfElseStatement_IfBranch)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyIfElseStatement_ElseBranch)
 {
     LLVMTypeAnalyzer analyzer;
-    LLVMVariablePtr varPtr;
+    Variable var("", "");
     LLVMInstructionList list;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
@@ -101,13 +100,13 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyIfElseStatement_ElseBranch)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, elseStart.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, elseStart.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyLoopUnknownType)
 {
     LLVMTypeAnalyzer analyzer;
-    LLVMVariablePtr varPtr;
+    Variable var("", "");
     LLVMInstructionList list;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
@@ -116,14 +115,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyLoopUnknownType)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NoWriteOperations)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
+    Variable var("", "");
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -134,16 +133,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NoWriteOperations)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteSameTypeNumber)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -157,16 +154,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteSameTypeNumber)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteSameTypeBool)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -180,16 +175,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteSameTypeBool)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::Bool);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::Bool);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteSameTypeString)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -203,16 +196,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteSameTypeString)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::String), Compiler::StaticType::String);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::String), Compiler::StaticType::String);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteStringOptimization)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -227,17 +218,15 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteStringOptimization)
     list.addInstruction(end);
 
     // Although string is assigned, it's constant and represents a number
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteMultipleVariables)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var1("", "");
     Variable var2("", "");
-    varPtr.var = &var1;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -259,16 +248,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteMultipleVariables)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteFromUnknownType)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -282,16 +269,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteFromUnknownType)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteToUnknownType)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -305,16 +290,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteToUnknownType)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteUnknownToUnknownType)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -328,16 +311,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteUnknownToUnknownType)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeNumberToString)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -351,16 +332,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeNumberToS
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeStringToNumber)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -374,16 +353,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeStringToN
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::String), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::String), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeNumberToBool)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -397,16 +374,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeNumberToB
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Bool);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Bool);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeBoolToNumber)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -420,16 +395,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeBoolToNum
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeBoolToString)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -443,16 +416,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeBoolToStr
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::String);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::String);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeStringToBool)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -466,16 +437,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeStringToB
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::String), Compiler::StaticType::Bool);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::String), Compiler::StaticType::Bool);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteSameType_IfStatement)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
     list.addInstruction(start);
@@ -489,16 +458,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteSameType_IfStatement)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentType_IfStatement)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
     list.addInstruction(start);
@@ -512,16 +479,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentType_IfStatem
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::String), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::String), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameTypeNumber)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -544,16 +509,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameTypeNumber)
     list.addInstruction(end);
 
     // Should return false because final assignment is compatible with pre-loop Number type
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameTypeString)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -576,16 +539,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameTypeString)
     list.addInstruction(end);
 
     // Should return false because final assignment is compatible with pre-loop String type
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::String), Compiler::StaticType::String);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::String), Compiler::StaticType::String);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameTypeUnknown)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -608,16 +569,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameTypeUnknown)
     list.addInstruction(end);
 
     // Should return false because final assignment is compatible with pre-loop String type
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::String), Compiler::StaticType::String);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::String), Compiler::StaticType::String);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesWithStringOptimization)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -640,16 +599,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesWithStringOptimizat
     list.addInstruction(end);
 
     // Should return false because final assignment is optimized to Number type
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesNumberToString)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -672,16 +629,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesNumberToString)
     list.addInstruction(end);
 
     // Should return true because final assignment is incompatible with pre-loop Number type
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesBoolToNumber)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -703,16 +658,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesBoolToNumber)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesBoolToString)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -734,16 +687,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesBoolToString)
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::String);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::String);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameType_IfStatement)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
     list.addInstruction(start);
@@ -766,16 +717,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameType_IfStatemen
     list.addInstruction(end);
 
     // Should return false because final assignment is compatible with Number type
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameType_IfBranch)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
     list.addInstruction(start);
@@ -808,16 +757,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameType_IfBranch)
     list.addInstruction(end);
 
     // Should return false because final assignment is compatible with Number type
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameType_ElseBranch)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
     list.addInstruction(start);
@@ -850,16 +797,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameType_ElseBranch
     list.addInstruction(end);
 
     // Should return false because final assignment is compatible with Number type
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, elseStart.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, elseStart.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesDifferentTypes_IfStatement)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
     list.addInstruction(start);
@@ -881,16 +826,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesDifferentTypes_IfSt
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::String);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::String);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesDifferentTypes_IfBranch)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
     list.addInstruction(start);
@@ -922,16 +865,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesDifferentTypes_IfBr
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::String);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::String);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesDifferentTypes_ElseBranch)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
     list.addInstruction(start);
@@ -963,16 +904,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesDifferentTypes_Else
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, elseStart.get(), Compiler::StaticType::Bool), Compiler::StaticType::String);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, elseStart.get(), Compiler::StaticType::Bool), Compiler::StaticType::String);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoop_TypeChangeInIfBranch)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -1004,16 +943,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoop_TypeChangeInIfB
     list.addInstruction(end);
 
     // Returns unknown type because the type-changing branch might or might not run
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoop_TypeChangeInElseBranch)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -1045,16 +982,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoop_TypeChangeInEls
     list.addInstruction(end);
 
     // Returns unknown type because the type-changing branch might or might not run
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoop_IfElseWithoutTypeChange)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
     list.addInstruction(start);
@@ -1085,16 +1020,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoop_IfElseWithoutTy
     auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(end);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopWithTypeChange)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     // Outer loop begin
     auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
@@ -1126,16 +1059,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopWithTypeChange)
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopWithoutTypeChange)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     // Outer loop begin
     auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginWhileLoop, nullptr, false);
@@ -1167,16 +1098,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopWithoutTypeChange)
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopTypeChangesButResets)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     // Outer loop begin
     auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
@@ -1215,16 +1144,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopTypeChangesButResets)
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopTypeChangesAndDoesNotReset)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     // Outer loop begin
     auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
@@ -1263,16 +1190,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopTypeChangesAndDoesNotRe
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopWithTypeChangeBeforeLoop)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     // Outer loop begin
     auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false);
@@ -1305,16 +1230,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopWithTypeChangeBeforeLoo
     list.addInstruction(outerEnd);
 
     // Returns unknown type because loops can be skipped
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoopWithTypeChangeBeforeLoop_TypeChangeInIfBranch)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     // Outer loop begin
     auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false);
@@ -1351,16 +1274,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoopWithTypeChangeBe
     list.addInstruction(outerEnd);
 
     // Returns unknown type because if statements can be skipped
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoopWithTypeChangeBeforeLoop_TypeChangeInElseBranch)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     // Outer loop begin
     auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false);
@@ -1397,16 +1318,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoopWithTypeChangeBe
     list.addInstruction(outerEnd);
 
     // Returns unknown type because if statements can be skipped
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoopWithTypeChangeBeforeLoop_TypeChangeInBothBranches)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     // Outer loop begin
     auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false);
@@ -1449,16 +1368,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoopWithTypeChangeBe
     list.addInstruction(outerEnd);
 
     // Returns number type because the type always changes to number
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedLoopsWithTypeChange)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     // Outer loop begin
     auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
@@ -1505,16 +1422,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedLoopsWithTypeChange
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedLoopsWithTypeChangeButTypeReset)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     // Outer loop begin
     auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
@@ -1561,16 +1476,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedLoopsWithTypeChange
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedIfStatementsWithTypeChange_IfBranch)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     // Outer if statement begin
     auto outerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
@@ -1628,16 +1541,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedIfStatementsWithTyp
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerIf.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerIf.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedIfStatementsWithTypeChange_ElseBranch)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     // Outer if statement begin
     auto outerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
@@ -1695,16 +1606,14 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedIfStatementsWithTyp
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerIf.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerIf.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
 }
 
 TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedIfStatementsWithoutTypeChange)
 {
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
-    LLVMVariablePtr varPtr;
     Variable var("", "");
-    varPtr.var = &var;
 
     // Outer if statement begin
     auto outerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
@@ -1762,7 +1671,7 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedIfStatementsWithout
     auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
     list.addInstruction(outerEnd);
 
-    ASSERT_EQ(analyzer.variableTypeAfterBranch(&varPtr, outerIf.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerIf.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
 // TODO: Handle cross-variable dependencies

From e8b26f5f2c66d3c29b13eb705d121ac23fe85f65 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Sat, 26 Jul 2025 13:13:05 +0200
Subject: [PATCH 34/79] Revert "LLVMCodeBuilder: Store variable pointer in
 LLVMVariablePtr"

This reverts commit b419577f4b41c74596f9408cc5440e1ba6f15f5a.
---
 src/engine/internal/llvm/llvmcodebuilder.cpp | 8 ++------
 src/engine/internal/llvm/llvmvariableptr.h   | 1 -
 2 files changed, 2 insertions(+), 7 deletions(-)

diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp
index f39ad665..b61a477b 100644
--- a/src/engine/internal/llvm/llvmcodebuilder.cpp
+++ b/src/engine/internal/llvm/llvmcodebuilder.cpp
@@ -1448,10 +1448,8 @@ CompilerValue *LLVMCodeBuilder::addVariableValue(Variable *variable)
     auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, currentLoopScope(), m_loopCondition);
     ins->workVariable = variable;
 
-    if (m_variablePtrs.find(variable) == m_variablePtrs.cend()) {
+    if (m_variablePtrs.find(variable) == m_variablePtrs.cend())
         m_variablePtrs[variable] = LLVMVariablePtr();
-        m_variablePtrs[variable].var = variable;
-    }
 
     auto ret = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
     ret->isRawValue = false;
@@ -1733,10 +1731,8 @@ void LLVMCodeBuilder::createVariableWrite(Variable *variable, CompilerValue *val
     ins.workVariable = variable;
     createOp(ins, Compiler::StaticType::Void, Compiler::StaticType::Unknown, { value });
 
-    if (m_variablePtrs.find(variable) == m_variablePtrs.cend()) {
+    if (m_variablePtrs.find(variable) == m_variablePtrs.cend())
         m_variablePtrs[variable] = LLVMVariablePtr();
-        m_variablePtrs[variable].var = variable;
-    }
 
     if (m_loopScope >= 0) {
         auto scope = m_loopScopes[m_loopScope];
diff --git a/src/engine/internal/llvm/llvmvariableptr.h b/src/engine/internal/llvm/llvmvariableptr.h
index b6da2a30..9907a5aa 100644
--- a/src/engine/internal/llvm/llvmvariableptr.h
+++ b/src/engine/internal/llvm/llvmvariableptr.h
@@ -20,7 +20,6 @@ class LLVMInstruction;
 
 struct LLVMVariablePtr
 {
-        Variable *var = nullptr;
         llvm::Value *stackPtr = nullptr;
         llvm::Value *heapPtr = nullptr;
         Compiler::StaticType type = Compiler::StaticType::Unknown;

From e89f882967d3397b2bbe08c0d3a519b8f079cc03 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Sat, 26 Jul 2025 13:32:25 +0200
Subject: [PATCH 35/79] LLVMTypeAnalyzer: Handle cross-variable dependencies

---
 src/engine/internal/llvm/llvmtypeanalyzer.cpp | 100 ++-
 src/engine/internal/llvm/llvmtypeanalyzer.h   |  14 +-
 test/llvm/type_analyzer/variabletype_test.cpp | 388 ++++++++++-
 .../variabletypeafterbranch_test.cpp          | 616 +++++++++++++++++-
 4 files changed, 1091 insertions(+), 27 deletions(-)

diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
index fa295e6b..5072eb22 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
@@ -9,10 +9,39 @@ static const std::unordered_set<LLVMInstruction::Type>
     BEGIN_LOOP_INSTRUCTIONS = { LLVMInstruction::Type::BeginRepeatLoop, LLVMInstruction::Type::BeginWhileLoop, LLVMInstruction::Type::BeginRepeatUntilLoop };
 
 Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType) const
+{
+    InstructionSet visitedInstructions;
+    return variableType(var, pos, previousType, visitedInstructions);
+}
+
+Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType) const
+{
+    InstructionSet visitedInstructions;
+    return variableTypeAfterBranch(var, start, previousType, visitedInstructions);
+}
+
+Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const
 {
     if (!var || !pos)
         return Compiler::StaticType::Unknown;
 
+    /*
+     * If the given instruction has already been processed,
+     * it means there's a case like this:
+     * x = x
+     *
+     * or this:
+     * x = y
+     * ...
+     * y = x
+     */
+    if (visitedInstructions.find(pos) != visitedInstructions.cend()) {
+        // Circular dependencies are rare (and bad) so don't optimize them
+        return Compiler::StaticType::Unknown;
+    }
+
+    visitedInstructions.insert(pos);
+
     // Check the last write operation before the instruction
     LLVMInstruction *ins = pos;
     LLVMInstruction *write = nullptr;
@@ -35,7 +64,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstructi
             firstElseBranch = ins;
             ins = skipBranch(ins);
             continue;
-        } else if (isVariableWrite(ins, var)) {
+        } else if (isVariableWrite(ins, var) && !isWriteNoOp(ins)) {
             if (level <= 0) { // ignore nested branches (they're handled by the branch analyzer)
                 write = ins;
                 break;
@@ -50,14 +79,14 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstructi
         bool ignoreWriteAfterPos = (isIfStart(firstBranch) && firstBranch == ourBranch);
 
         if (write)
-            previousType = writeValueType(write); // write operation overrides previous type
+            previousType = writeValueType(write, visitedInstructions); // write operation overrides previous type
 
         Compiler::StaticType firstBranchType = previousType;
         Compiler::StaticType elseBranchType = previousType;
 
         if (!ignoreWriteAfterPos) {
-            firstBranchType = variableTypeAfterBranch(var, firstBranch, previousType);
-            elseBranchType = variableTypeAfterBranch(var, firstElseBranch, previousType);
+            firstBranchType = variableTypeAfterBranch(var, firstBranch, previousType, visitedInstructions);
+            elseBranchType = variableTypeAfterBranch(var, firstElseBranch, previousType, visitedInstructions);
         }
 
         if (typesMatch(firstBranchType, elseBranchType))
@@ -66,14 +95,14 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstructi
             return Compiler::StaticType::Unknown;
     } else if (write) {
         // There wasn't any branch found, so we can just check the last write operation
-        return writeValueType(write);
+        return writeValueType(write, visitedInstructions);
     }
 
     // No write operation found
     return previousType;
 }
 
-Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType) const
+Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const
 {
     if (!var || !start)
         return previousType;
@@ -102,10 +131,10 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(Variable *var, LL
 
     // Process the branch from end
     bool write = false; // only used internally (the compiler doesn't need this)
-    return variableTypeAfterBranchFromEnd(var, ins, previousType, write);
+    return variableTypeAfterBranchFromEnd(var, ins, previousType, write, visitedInstructions);
 }
 
-Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable *var, LLVMInstruction *end, Compiler::StaticType previousType, bool &write) const
+Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable *var, LLVMInstruction *end, Compiler::StaticType previousType, bool &write, InstructionSet &visitedInstructions) const
 {
     // Find the last write instruction
     LLVMInstruction *ins = end->previous;
@@ -114,7 +143,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable *
     while (ins && !isLoopStart(ins) && !isIfStart(ins)) {
         if (isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) {
             // Process the nested loop or if statement
-            Compiler::StaticType ret = variableTypeAfterBranchFromEnd(var, ins, previousType, write);
+            Compiler::StaticType ret = variableTypeAfterBranchFromEnd(var, ins, previousType, write, visitedInstructions);
 
             if (typesMatch(ret, previousType)) {
                 if (write)
@@ -126,7 +155,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable *
 
             if (isElse(ins)) {
                 // Process if branch (the else branch is already processed)
-                ret = variableTypeAfterBranchFromEnd(var, ins, previousType, write);
+                ret = variableTypeAfterBranchFromEnd(var, ins, previousType, write, visitedInstructions);
 
                 if (typesMatch(ret, previousType)) {
                     if (write) {
@@ -140,9 +169,9 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable *
 
                 ins = skipBranch(ins);
             }
-        } else if (isVariableWrite(ins, var)) {
+        } else if (isVariableWrite(ins, var) && !isWriteNoOp(ins)) {
             // Variable write instruction
-            Compiler::StaticType writeType = writeValueType(ins);
+            Compiler::StaticType writeType = writeValueType(ins, visitedInstructions);
             write = true;
 
             if (typesMatch(writeType, previousType))
@@ -208,6 +237,11 @@ bool LLVMTypeAnalyzer::isIfEnd(LLVMInstruction *ins) const
     return (ins->type == LLVMInstruction::Type::EndIf);
 }
 
+bool LLVMTypeAnalyzer::isVariableRead(LLVMInstruction *ins) const
+{
+    return (ins->type == LLVMInstruction::Type::ReadVariable);
+}
+
 bool LLVMTypeAnalyzer::isVariableWrite(LLVMInstruction *ins, Variable *var) const
 {
     return (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == var);
@@ -227,12 +261,40 @@ Compiler::StaticType LLVMTypeAnalyzer::optimizeRegisterType(LLVMRegister *reg) c
     return ret;
 }
 
-Compiler::StaticType LLVMTypeAnalyzer::writeValueType(LLVMInstruction *ins) const
+bool LLVMTypeAnalyzer::isWriteNoOp(LLVMInstruction *ins) const
 {
     assert(ins);
     assert(!ins->args.empty());
     const auto arg = ins->args.back().second; // value is always the last argument in variable/list write instructions
-    return optimizeRegisterType(arg);
+
+    if (arg->instruction) {
+        // TODO: Handle list item
+        if (isVariableRead(arg->instruction.get())) {
+            // Self-assignment is a no-op
+            return (ins->workVariable == arg->instruction->workVariable);
+        }
+    }
+
+    return false;
+}
+
+Compiler::StaticType LLVMTypeAnalyzer::writeValueType(LLVMInstruction *ins, InstructionSet &visitedInstructions) const
+{
+    assert(ins);
+    assert(!ins->args.empty());
+    const auto arg = ins->args.back().second; // value is always the last argument in variable/list write instructions
+
+    if (arg->instruction) {
+        // TODO: Handle list item
+        if (isVariableRead(arg->instruction.get())) {
+            // If this is a variable read instruction, recursively get the variable type
+            return variableType(arg->instruction->workVariable, arg->instruction.get(), Compiler::StaticType::Unknown, visitedInstructions);
+        } else {
+            // TODO: Use the instruction return register
+            return optimizeRegisterType(arg);
+        }
+    } else
+        return optimizeRegisterType(arg);
 }
 
 bool LLVMTypeAnalyzer::typesMatch(Compiler::StaticType a, Compiler::StaticType b) const
@@ -241,13 +303,7 @@ bool LLVMTypeAnalyzer::typesMatch(Compiler::StaticType a, Compiler::StaticType b
     return (a == b) && (a != Compiler::StaticType::Unknown);
 }
 
-bool LLVMTypeAnalyzer::writeTypesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const
+bool LLVMTypeAnalyzer::writeTypesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType, InstructionSet &visitedInstructions) const
 {
-    // auto argIns = arg->instruction;
-
-    // TODO: Handle cross-variable dependencies
-    /*if (argIns && (argIns->type == LLVMInstruction::Type::ReadVariable || argIns->type == LLVMInstruction::Type::GetListItem))
-        return isVarOrListTypeSafe(argIns.get(), expectedType, log, c);*/
-
-    return typesMatch(writeValueType(ins), expectedType);
+    return typesMatch(writeValueType(ins, visitedInstructions), expectedType);
 }
diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.h b/src/engine/internal/llvm/llvmtypeanalyzer.h
index 3cb4cc4e..ac32565b 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.h
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.h
@@ -15,19 +15,27 @@ class LLVMTypeAnalyzer
         Compiler::StaticType variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType) const;
 
     private:
-        Compiler::StaticType variableTypeAfterBranchFromEnd(Variable *var, LLVMInstruction *end, Compiler::StaticType previousType, bool &write) const;
+        using InstructionSet = std::unordered_set<LLVMInstruction *>;
+
+        Compiler::StaticType variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const;
+        Compiler::StaticType variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const;
+        Compiler::StaticType variableTypeAfterBranchFromEnd(Variable *var, LLVMInstruction *end, Compiler::StaticType previousType, bool &write, InstructionSet &visitedInstructions) const;
+
         LLVMInstruction *skipBranch(LLVMInstruction *pos) const;
+
         bool isLoopStart(LLVMInstruction *ins) const;
         bool isLoopEnd(LLVMInstruction *ins) const;
         bool isIfStart(LLVMInstruction *ins) const;
         bool isElse(LLVMInstruction *ins) const;
         bool isIfEnd(LLVMInstruction *ins) const;
+        bool isVariableRead(LLVMInstruction *ins) const;
         bool isVariableWrite(LLVMInstruction *ins, Variable *var) const;
 
         Compiler::StaticType optimizeRegisterType(LLVMRegister *reg) const;
-        Compiler::StaticType writeValueType(LLVMInstruction *ins) const;
+        bool isWriteNoOp(LLVMInstruction *ins) const;
+        Compiler::StaticType writeValueType(LLVMInstruction *ins, InstructionSet &visitedInstructions) const;
         bool typesMatch(Compiler::StaticType a, Compiler::StaticType b) const;
-        bool writeTypesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType) const;
+        bool writeTypesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType, InstructionSet &visitedInstructions) const;
 };
 
 } // namespace libscratchcpp
diff --git a/test/llvm/type_analyzer/variabletype_test.cpp b/test/llvm/type_analyzer/variabletype_test.cpp
index 65037f60..0bba27bc 100644
--- a/test/llvm/type_analyzer/variabletype_test.cpp
+++ b/test/llvm/type_analyzer/variabletype_test.cpp
@@ -1766,4 +1766,390 @@ TEST(LLVMTypeAnalyzer_VariableType, SameTypeIfElseInLoopWithTypeChange)
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
 }
 
-// TODO: Handle cross-variable dependencies
+TEST(LLVMTypeAnalyzer_VariableType, CrossVariableDependency_SimpleAssignment)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", ""), var2("", "");
+
+    // First write: var2 = "test" (String type)
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "test");
+    setVar2->workVariable = &var2;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar2);
+
+    // Second write: var1 = var2 (cross-variable dependency)
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    list.addInstruction(readVar2);
+    readVar2->workVariable = &var2;
+
+    LLVMRegister var2Value(Compiler::StaticType::Unknown);
+    var2Value.isRawValue = false;
+    var2Value.instruction = readVar2;
+    readVar2->functionReturnReg = &var2Value;
+
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value });
+    list.addInstruction(setVar1);
+
+    // Query position after the assignment
+    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(queryPos);
+
+    // var1 should have String type due to cross-variable dependency
+    ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, CrossVariableDependency_TypeMismatch)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", ""), var2("", "");
+
+    // First write: var2 = "test" (String type)
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "test");
+    setVar2->workVariable = &var2;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar2);
+
+    // Second write: var1 = var2 (cross-variable dependency with type mismatch)
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    list.addInstruction(readVar2);
+    readVar2->workVariable = &var2;
+
+    LLVMRegister var2Value(Compiler::StaticType::Unknown);
+    var2Value.isRawValue = false;
+    var2Value.instruction = readVar2;
+    readVar2->functionReturnReg = &var2Value;
+
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value });
+    list.addInstruction(setVar1);
+
+    // Query position after the assignment
+    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(queryPos);
+
+    // var1 should have String type (different from Number previousType)
+    ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, CrossVariableDependency_QueryBeforeAssignment)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", ""), var2("", "");
+
+    // Query position before any assignments
+    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(queryPos);
+
+    // First write: var2 = "test" (String type) - after query position
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "test");
+    setVar2->workVariable = &var2;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar2);
+
+    // Second write: var1 = var2 (cross-variable dependency) - after query position
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    list.addInstruction(readVar2);
+    readVar2->workVariable = &var2;
+
+    LLVMRegister var2Value(Compiler::StaticType::Unknown);
+    var2Value.isRawValue = false;
+    var2Value.instruction = readVar2;
+    readVar2->functionReturnReg = &var2Value;
+
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value });
+    list.addInstruction(setVar1);
+
+    // var1 should have the previous type since assignments are after query position
+    ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, CrossVariableDependency_ChainedAssignments)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", ""), var2("", ""), var3("", "");
+
+    // First write: var3 = 42 (Number type)
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
+    setVar3->workVariable = &var3;
+    setVar3->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar3);
+
+    // Second write: var2 = var3 (cross-variable dependency)
+    auto readVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    list.addInstruction(readVar3);
+    readVar3->workVariable = &var3;
+
+    LLVMRegister var3Value(Compiler::StaticType::Unknown);
+    var3Value.isRawValue = false;
+    var3Value.instruction = readVar3;
+    readVar3->functionReturnReg = &var3Value;
+
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar2->workVariable = &var2;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &var3Value });
+    list.addInstruction(setVar2);
+
+    // Third write: var1 = var2 (chained cross-variable dependency)
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    list.addInstruction(readVar2);
+    readVar2->workVariable = &var2;
+
+    LLVMRegister var2Value(Compiler::StaticType::Unknown);
+    var2Value.isRawValue = false;
+    var2Value.instruction = readVar2;
+    readVar2->functionReturnReg = &var2Value;
+
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value });
+    list.addInstruction(setVar1);
+
+    // Query position after all assignments
+    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(queryPos);
+
+    // var1 should have Number type through the chain var1 = var2 = var3 = 42
+    ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, CrossVariableDependency_CircularReference)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", ""), var2("", "");
+
+    // First write: var1 = var2 (circular dependency setup)
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    list.addInstruction(readVar2);
+    readVar2->workVariable = &var2;
+
+    LLVMRegister var2Value(Compiler::StaticType::Unknown);
+    var2Value.isRawValue = false;
+    var2Value.instruction = readVar2;
+    readVar2->functionReturnReg = &var2Value;
+
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value });
+    list.addInstruction(setVar1);
+
+    // Second write: var2 = var1 (completes circular dependency)
+    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    list.addInstruction(readVar1);
+    readVar1->workVariable = &var1;
+
+    LLVMRegister var1Value(Compiler::StaticType::Unknown);
+    var1Value.isRawValue = false;
+    var1Value.instruction = readVar1;
+    readVar1->functionReturnReg = &var1Value;
+
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar2->workVariable = &var2;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &var1Value });
+    list.addInstruction(setVar2);
+
+    // Query position after circular assignments
+    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(queryPos);
+
+    // Should return Unknown due to circular dependency
+    ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, CrossVariableDependency_InIfStatement_QueryInside)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", ""), var2("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(start);
+
+    // First write: var2 = 3.14 (Number type)
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 3.14);
+    setVar2->workVariable = &var2;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar2);
+
+    // Second write: var1 = var2 (cross-variable dependency in if statement)
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    list.addInstruction(readVar2);
+    readVar2->workVariable = &var2;
+
+    LLVMRegister var2Value(Compiler::StaticType::Unknown);
+    var2Value.isRawValue = false;
+    var2Value.instruction = readVar2;
+    readVar2->functionReturnReg = &var2Value;
+
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value });
+    list.addInstruction(setVar1);
+
+    // Query position inside if statement after assignments
+    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(queryPos);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(end);
+
+    // var1 should have Number type from cross-variable dependency
+    ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::String), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, CrossVariableDependency_InIfStatement_QueryOutside)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", ""), var2("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(start);
+
+    // First write: var2 = 3.14 (Number type)
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 3.14);
+    setVar2->workVariable = &var2;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar2);
+
+    // Second write: var1 = var2 (cross-variable dependency in if statement)
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    list.addInstruction(readVar2);
+    readVar2->workVariable = &var2;
+
+    LLVMRegister var2Value(Compiler::StaticType::Unknown);
+    var2Value.isRawValue = false;
+    var2Value.instruction = readVar2;
+    readVar2->functionReturnReg = &var2Value;
+
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value });
+    list.addInstruction(setVar1);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(end);
+
+    // Query position outside if statement after it ends
+    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(queryPos);
+
+    // var1 should return Unknown because the write is inside an if statement that may not execute
+    ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::String), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, SelfAssignment)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", "");
+
+    // No-op: var1 = var1
+    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    list.addInstruction(readVar1);
+    readVar1->workVariable = &var1;
+
+    LLVMRegister var1Value(Compiler::StaticType::Unknown);
+    var1Value.isRawValue = false;
+    var1Value.instruction = readVar1;
+    readVar1->functionReturnReg = &var1Value;
+
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &var1Value });
+    list.addInstruction(setVar1);
+
+    // Query position after self-assignment
+    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(queryPos);
+
+    // Should return the previous type because the write is a no-op
+    ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::String), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, SelfAssignmentWithTypeChange_Before)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", "");
+
+    // First write: var1 = 3.14 (Number type)
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 3.14);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // No-op: var1 = var1
+    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    list.addInstruction(readVar1);
+    readVar1->workVariable = &var1;
+
+    LLVMRegister var1Value(Compiler::StaticType::Unknown);
+    var1Value.isRawValue = false;
+    var1Value.instruction = readVar1;
+    readVar1->functionReturnReg = &var1Value;
+
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar2->workVariable = &var1;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &var1Value });
+    list.addInstruction(setVar2);
+
+    // Query position after self-assignment
+    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(queryPos);
+
+    // Should return the previous type (number) because the write is a no-op
+    ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::String), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, SelfAssignmentWithTypeChange_After)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", "");
+
+    // No-op: var1 = var1
+    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    list.addInstruction(readVar1);
+    readVar1->workVariable = &var1;
+
+    LLVMRegister var1Value(Compiler::StaticType::Unknown);
+    var1Value.isRawValue = false;
+    var1Value.instruction = readVar1;
+    readVar1->functionReturnReg = &var1Value;
+
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &var1Value });
+    list.addInstruction(setVar1);
+
+    // var1 = 3.14 (Number type)
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 3.14);
+    setVar2->workVariable = &var1;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    // Query position after real assignment
+    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(queryPos);
+
+    // Should return number because it's assigned after the no-op
+    ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::String), Compiler::StaticType::Number);
+}
diff --git a/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp b/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp
index dc3db515..dc30be45 100644
--- a/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp
+++ b/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp
@@ -1674,4 +1674,618 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedIfStatementsWithout
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerIf.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
 }
 
-// TODO: Handle cross-variable dependencies
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_SimpleAssignment)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", ""), var2("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    // First write: var2 = "test" (String type)
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "test");
+    setVar2->workVariable = &var2;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar2);
+
+    // Second write: var1 = var2 (cross-variable dependency)
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    list.addInstruction(readVar2);
+    readVar2->workVariable = &var2;
+
+    LLVMRegister var2Value(Compiler::StaticType::Unknown);
+    var2Value.isRawValue = false;
+    var2Value.instruction = readVar2;
+    readVar2->functionReturnReg = &var2Value;
+
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value });
+    list.addInstruction(setVar1);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    // var1 should have String type due to cross-variable dependency
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::String), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_TypeMismatch)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", ""), var2("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    // First write: var2 = "test" (String type)
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "test");
+    setVar2->workVariable = &var2;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar2);
+
+    // Second write: var1 = var2 (cross-variable dependency with type mismatch)
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    list.addInstruction(readVar2);
+    readVar2->workVariable = &var2;
+
+    LLVMRegister var2Value(Compiler::StaticType::Unknown);
+    var2Value.isRawValue = false;
+    var2Value.instruction = readVar2;
+    readVar2->functionReturnReg = &var2Value;
+
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value });
+    list.addInstruction(setVar1);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    // var1 should have String type (incompatible with Number pre-loop type)
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_SimpleAssignmentBeforeTypeChange)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", ""), var2("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    // var1 = var2
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    list.addInstruction(readVar2);
+    readVar2->workVariable = &var2;
+
+    LLVMRegister var2Value(Compiler::StaticType::Unknown);
+    var2Value.isRawValue = false;
+    var2Value.instruction = readVar2;
+    readVar2->functionReturnReg = &var2Value;
+
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value });
+    list.addInstruction(setVar1);
+
+    // var2 = 5.2 (type resets to number)
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 5.2);
+    setVar2->workVariable = &var2;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    // Although the type of var2 is changed to number, it's unknown before the first iteration
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_ChainedAssignments)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", ""), var2("", ""), var3("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    // First write: var3 = 42 (Number type)
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
+    setVar3->workVariable = &var3;
+    setVar3->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar3);
+
+    // Second write: var2 = var3 (cross-variable dependency)
+    auto readVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    list.addInstruction(readVar3);
+    readVar3->workVariable = &var3;
+
+    LLVMRegister var3Value(Compiler::StaticType::Unknown);
+    var3Value.isRawValue = false;
+    var3Value.instruction = readVar3;
+    readVar3->functionReturnReg = &var3Value;
+
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar2->workVariable = &var2;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &var3Value });
+    list.addInstruction(setVar2);
+
+    // Third write: var1 = var2 (chained cross-variable dependency)
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    list.addInstruction(readVar2);
+    readVar2->workVariable = &var2;
+
+    LLVMRegister var2Value(Compiler::StaticType::Unknown);
+    var2Value.isRawValue = false;
+    var2Value.instruction = readVar2;
+    readVar2->functionReturnReg = &var2Value;
+
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value });
+    list.addInstruction(setVar1);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    // var1 should have Number type through the chain var1 = var2 = var3 = 42
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_CircularReference)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", ""), var2("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    // First write: var1 = var2 (circular dependency setup)
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    list.addInstruction(readVar2);
+    readVar2->workVariable = &var2;
+
+    LLVMRegister var2Value(Compiler::StaticType::Unknown);
+    var2Value.isRawValue = false;
+    var2Value.instruction = readVar2;
+    readVar2->functionReturnReg = &var2Value;
+
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value });
+    list.addInstruction(setVar1);
+
+    // Second write: var2 = var1 (completes circular dependency)
+    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    list.addInstruction(readVar1);
+    readVar1->workVariable = &var1;
+
+    LLVMRegister var1Value(Compiler::StaticType::Unknown);
+    var1Value.isRawValue = false;
+    var1Value.instruction = readVar1;
+    readVar1->functionReturnReg = &var1Value;
+
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar2->workVariable = &var2;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &var1Value });
+    list.addInstruction(setVar2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    // Should return Unknown due to circular dependency
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_CircularReference_KnownTypes)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", ""), var2("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    // var1 is a number
+    auto setupVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
+    setupVar1->workVariable = &var1;
+    setupVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setupVar1);
+
+    // var2 is a number
+    auto setupVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 42);
+    setupVar2->workVariable = &var2;
+    setupVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setupVar2);
+
+    // First write: var1 = var2 (circular dependency setup)
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    list.addInstruction(readVar2);
+    readVar2->workVariable = &var2;
+
+    LLVMRegister var2Value(Compiler::StaticType::Unknown);
+    var2Value.isRawValue = false;
+    var2Value.instruction = readVar2;
+    readVar2->functionReturnReg = &var2Value;
+
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value });
+    list.addInstruction(setVar1);
+
+    // Second write: var2 = var1 (completes circular dependency)
+    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    list.addInstruction(readVar1);
+    readVar1->workVariable = &var1;
+
+    LLVMRegister var1Value(Compiler::StaticType::Unknown);
+    var1Value.isRawValue = false;
+    var1Value.instruction = readVar1;
+    readVar1->functionReturnReg = &var1Value;
+
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar2->workVariable = &var2;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &var1Value });
+    list.addInstruction(setVar2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    // Although there is a circular dependency, the types of both variables are known
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::String), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_CircularReference_FirstAssignedTypeKnown)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", ""), var2("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    // var1: unknown type
+
+    // var2 is a number
+    auto setupVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 42);
+    setupVar2->workVariable = &var2;
+    setupVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setupVar2);
+
+    // First write: var1 = var2 (circular dependency setup)
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    list.addInstruction(readVar2);
+    readVar2->workVariable = &var2;
+
+    LLVMRegister var2Value(Compiler::StaticType::Unknown);
+    var2Value.isRawValue = false;
+    var2Value.instruction = readVar2;
+    readVar2->functionReturnReg = &var2Value;
+
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value });
+    list.addInstruction(setVar1);
+
+    // Second write: var2 = var1 (completes circular dependency)
+    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    list.addInstruction(readVar1);
+    readVar1->workVariable = &var1;
+
+    LLVMRegister var1Value(Compiler::StaticType::Unknown);
+    var1Value.isRawValue = false;
+    var1Value.instruction = readVar1;
+    readVar1->functionReturnReg = &var1Value;
+
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar2->workVariable = &var2;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &var1Value });
+    list.addInstruction(setVar2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    // Although there is a circular dependency, the type of var2 is known and this variable is assigned to var1
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::String), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_CircularReference_AssignedTypeUnknown)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", ""), var2("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    // var1 is a number
+    auto setupVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
+    setupVar1->workVariable = &var1;
+    setupVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setupVar1);
+
+    // var2: unknown type
+
+    // First write: var1 = var2 (circular dependency setup)
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    list.addInstruction(readVar2);
+    readVar2->workVariable = &var2;
+
+    LLVMRegister var2Value(Compiler::StaticType::Unknown);
+    var2Value.isRawValue = false;
+    var2Value.instruction = readVar2;
+    readVar2->functionReturnReg = &var2Value;
+
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value });
+    list.addInstruction(setVar1);
+
+    // Second write: var2 = var1 (completes circular dependency)
+    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    list.addInstruction(readVar1);
+    readVar1->workVariable = &var1;
+
+    LLVMRegister var1Value(Compiler::StaticType::Unknown);
+    var1Value.isRawValue = false;
+    var1Value.instruction = readVar1;
+    readVar1->functionReturnReg = &var1Value;
+
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar2->workVariable = &var2;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &var1Value });
+    list.addInstruction(setVar2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    // The type of var2 is not known and this variable is assigned to var1
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::String), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_ChainedCircularReference)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", ""), var2("", ""), var3("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    // First write: var1 = var2 (circular dependency setup)
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    list.addInstruction(readVar2);
+    readVar2->workVariable = &var2;
+
+    LLVMRegister var2Value(Compiler::StaticType::Unknown);
+    var2Value.isRawValue = false;
+    var2Value.instruction = readVar2;
+    readVar2->functionReturnReg = &var2Value;
+
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value });
+    list.addInstruction(setVar1);
+
+    // Second write: var2 = var3
+    auto readVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    list.addInstruction(readVar3);
+    readVar3->workVariable = &var3;
+
+    LLVMRegister var3Value(Compiler::StaticType::Unknown);
+    var3Value.isRawValue = false;
+    var3Value.instruction = readVar3;
+    readVar3->functionReturnReg = &var3Value;
+
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar2->workVariable = &var2;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &var3Value });
+    list.addInstruction(setVar2);
+
+    // Third write: var3 = var1 (completes circular dependency)
+    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    list.addInstruction(readVar1);
+    readVar1->workVariable = &var1;
+
+    LLVMRegister var1Value(Compiler::StaticType::Unknown);
+    var1Value.isRawValue = false;
+    var1Value.instruction = readVar1;
+    readVar1->functionReturnReg = &var1Value;
+
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar3->workVariable = &var3;
+    setVar3->args.push_back({ Compiler::StaticType::Unknown, &var1Value });
+    list.addInstruction(setVar3);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    // Should return Unknown due to circular dependency
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_InIfStatement)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", ""), var2("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(start);
+
+    // First write: var2 = 3.14 (Number type)
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 3.14);
+    setVar2->workVariable = &var2;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar2);
+
+    // Second write: var1 = var2 (cross-variable dependency in if statement)
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    list.addInstruction(readVar2);
+    readVar2->workVariable = &var2;
+
+    LLVMRegister var2Value(Compiler::StaticType::Unknown);
+    var2Value.isRawValue = false;
+    var2Value.instruction = readVar2;
+    readVar2->functionReturnReg = &var2Value;
+
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value });
+    list.addInstruction(setVar1);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(end);
+
+    // var1 should have Number type from cross-variable dependency
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::String), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SelfAssignment)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    // Start if statement
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(ifStart);
+
+    // No-op: var1 = var1
+    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    list.addInstruction(readVar1);
+    readVar1->workVariable = &var1;
+
+    LLVMRegister var1Value(Compiler::StaticType::Unknown);
+    var1Value.isRawValue = false;
+    var1Value.instruction = readVar1;
+    readVar1->functionReturnReg = &var1Value;
+
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &var1Value });
+    list.addInstruction(setVar1);
+
+    // End if statement
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(ifEnd);
+
+    // End loop
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    // Should return the previous type because the write is a no-op
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::String), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SelfAssignmentWithTypeChange_Before)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    // First write: var1 = 3.14 (Number type)
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 3.14);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    // Start if statement
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(ifStart);
+
+    // No-op: var1 = var1
+    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    list.addInstruction(readVar1);
+    readVar1->workVariable = &var1;
+
+    LLVMRegister var1Value(Compiler::StaticType::Unknown);
+    var1Value.isRawValue = false;
+    var1Value.instruction = readVar1;
+    readVar1->functionReturnReg = &var1Value;
+
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar2->workVariable = &var1;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &var1Value });
+    list.addInstruction(setVar2);
+
+    // End if statement
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(ifEnd);
+
+    // End loop
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    // Should return the previous type (number) because the write is a no-op
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::String), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SelfAssignmentWithTypeChange_After)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    // Start if statement
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(ifStart);
+
+    // No-op: var1 = var1
+    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    list.addInstruction(readVar1);
+    readVar1->workVariable = &var1;
+
+    LLVMRegister var1Value(Compiler::StaticType::Unknown);
+    var1Value.isRawValue = false;
+    var1Value.instruction = readVar1;
+    readVar1->functionReturnReg = &var1Value;
+
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &var1Value });
+    list.addInstruction(setVar1);
+
+    // End if statement
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(ifEnd);
+
+    // var1 = 3.14 (Number type)
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 3.14);
+    setVar2->workVariable = &var1;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    // End loop
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    // Should return number because it's assigned later in the loop
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::String), Compiler::StaticType::Number);
+}

From a76435b00b2be28ae7f84b3e4cdca59cb0d87242 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Sat, 26 Jul 2025 14:13:56 +0200
Subject: [PATCH 36/79] LLVMTypeAnalyzer: Add test cases for reporters assigned
 to variables

---
 src/engine/internal/llvm/llvmtypeanalyzer.cpp |   2 +-
 test/llvm/type_analyzer/variabletype_test.cpp | 245 ++++++++++++++++++
 .../variabletypeafterbranch_test.cpp          | 224 ++++++++++++++++
 3 files changed, 470 insertions(+), 1 deletion(-)

diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
index 5072eb22..aace9e48 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
@@ -290,7 +290,7 @@ Compiler::StaticType LLVMTypeAnalyzer::writeValueType(LLVMInstruction *ins, Inst
             // If this is a variable read instruction, recursively get the variable type
             return variableType(arg->instruction->workVariable, arg->instruction.get(), Compiler::StaticType::Unknown, visitedInstructions);
         } else {
-            // TODO: Use the instruction return register
+            // The write argument already has the instruction return type
             return optimizeRegisterType(arg);
         }
     } else
diff --git a/test/llvm/type_analyzer/variabletype_test.cpp b/test/llvm/type_analyzer/variabletype_test.cpp
index 0bba27bc..63739f6a 100644
--- a/test/llvm/type_analyzer/variabletype_test.cpp
+++ b/test/llvm/type_analyzer/variabletype_test.cpp
@@ -2153,3 +2153,248 @@ TEST(LLVMTypeAnalyzer_VariableType, SelfAssignmentWithTypeChange_After)
     // Should return number because it's assigned after the no-op
     ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::String), Compiler::StaticType::Number);
 }
+
+TEST(LLVMTypeAnalyzer_VariableType, InstructionReturnType_AddNumbers)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", "");
+
+    // Create add instruction: 5 + 3
+    auto addInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Add, nullptr, false);
+    LLVMConstantRegister operand1(Compiler::StaticType::Number, 5);
+    LLVMConstantRegister operand2(Compiler::StaticType::Number, 3);
+    addInstruction->args.push_back({ Compiler::StaticType::Number, &operand1 });
+    addInstruction->args.push_back({ Compiler::StaticType::Number, &operand2 });
+
+    // Set up return register for add instruction
+    LLVMRegister addResult(Compiler::StaticType::Number);
+    addResult.isRawValue = true;
+    addResult.instruction = addInstruction;
+    addInstruction->functionReturnReg = &addResult;
+    list.addInstruction(addInstruction);
+
+    // Assign add result to variable: var1 = (5 + 3)
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &addResult });
+    list.addInstruction(setVar1);
+
+    // Query position after the assignment
+    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(queryPos);
+
+    // var1 should have Number type from add instruction return
+    ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::String), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, InstructionReturnType_StringConcat)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", "");
+
+    // Create string concatenation instruction: "hello" + "world"
+    auto concatInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::StringConcat, nullptr, false);
+    LLVMConstantRegister str1(Compiler::StaticType::String, "hello");
+    LLVMConstantRegister str2(Compiler::StaticType::String, "world");
+    concatInstruction->args.push_back({ Compiler::StaticType::String, &str1 });
+    concatInstruction->args.push_back({ Compiler::StaticType::String, &str2 });
+
+    // Set up return register for concat instruction
+    LLVMRegister concatResult(Compiler::StaticType::String);
+    concatResult.isRawValue = true;
+    concatResult.instruction = concatInstruction;
+    concatInstruction->functionReturnReg = &concatResult;
+    list.addInstruction(concatInstruction);
+
+    // Assign concat result to variable: var1 = ("hello" + "world")
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &concatResult });
+    list.addInstruction(setVar1);
+
+    // Query position after the assignment
+    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(queryPos);
+
+    // var1 should have String type from concat instruction return
+    ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, InstructionReturnType_MathFunction)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", "");
+
+    // Create sqrt instruction: sqrt(16)
+    auto sqrtInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Sqrt, nullptr, false);
+    LLVMConstantRegister operand(Compiler::StaticType::Number, 16);
+    sqrtInstruction->args.push_back({ Compiler::StaticType::Number, &operand });
+
+    // Set up return register for sqrt instruction
+    LLVMRegister sqrtResult(Compiler::StaticType::Number);
+    sqrtResult.isRawValue = true;
+    sqrtResult.instruction = sqrtInstruction;
+    sqrtInstruction->functionReturnReg = &sqrtResult;
+    list.addInstruction(sqrtInstruction);
+
+    // Assign sqrt result to variable: var1 = sqrt(16)
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &sqrtResult });
+    list.addInstruction(setVar1);
+
+    // Query position after the assignment
+    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(queryPos);
+
+    // var1 should have Number type from sqrt instruction return
+    ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::String), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, InstructionReturnType_Comparison)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", "");
+
+    // Create comparison instruction: 5 > 3
+    auto cmpInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::CmpGT, nullptr, false);
+    LLVMConstantRegister operand1(Compiler::StaticType::Number, 5);
+    LLVMConstantRegister operand2(Compiler::StaticType::Number, 3);
+    cmpInstruction->args.push_back({ Compiler::StaticType::Number, &operand1 });
+    cmpInstruction->args.push_back({ Compiler::StaticType::Number, &operand2 });
+
+    // Set up return register for comparison instruction
+    LLVMRegister cmpResult(Compiler::StaticType::Bool);
+    cmpResult.isRawValue = true;
+    cmpResult.instruction = cmpInstruction;
+    cmpInstruction->functionReturnReg = &cmpResult;
+    list.addInstruction(cmpInstruction);
+
+    // Assign comparison result to variable: var1 = (5 > 3)
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &cmpResult });
+    list.addInstruction(setVar1);
+
+    // Query position after the assignment
+    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(queryPos);
+
+    // var1 should have Bool type from comparison instruction return
+    ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::Number), Compiler::StaticType::Bool);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, InstructionReturnType_FunctionCall)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", "");
+
+    // Create function call instruction
+    auto funcInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    funcInstruction->functionName = "some_reporter_function";
+    LLVMConstantRegister arg(Compiler::StaticType::Number, 42);
+    funcInstruction->args.push_back({ Compiler::StaticType::Number, &arg });
+
+    // Set up return register for function call
+    LLVMRegister funcResult(Compiler::StaticType::String);
+    funcResult.isRawValue = true;
+    funcResult.instruction = funcInstruction;
+    funcInstruction->functionReturnReg = &funcResult;
+    list.addInstruction(funcInstruction);
+
+    // Assign function result to variable: var1 = some_reporter_function(42)
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &funcResult });
+    list.addInstruction(setVar1);
+
+    // Query position after the assignment
+    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(queryPos);
+
+    // var1 should have String type from function call return
+    ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, InstructionReturnType_ChainedOperations)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", "");
+
+    // First operation: 5 + 3
+    auto addInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Add, nullptr, false);
+    LLVMConstantRegister operand1(Compiler::StaticType::Number, 5);
+    LLVMConstantRegister operand2(Compiler::StaticType::Number, 3);
+    addInstruction->args.push_back({ Compiler::StaticType::Number, &operand1 });
+    addInstruction->args.push_back({ Compiler::StaticType::Number, &operand2 });
+
+    LLVMRegister addResult(Compiler::StaticType::Number);
+    addResult.isRawValue = true;
+    addResult.instruction = addInstruction;
+    addInstruction->functionReturnReg = &addResult;
+    list.addInstruction(addInstruction);
+
+    // Second operation: (5 + 3) * 2
+    auto mulInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Mul, nullptr, false);
+    LLVMConstantRegister multiplier(Compiler::StaticType::Number, 2);
+    mulInstruction->args.push_back({ Compiler::StaticType::Unknown, &addResult });
+    mulInstruction->args.push_back({ Compiler::StaticType::Number, &multiplier });
+
+    LLVMRegister mulResult(Compiler::StaticType::Number);
+    mulResult.isRawValue = true;
+    mulResult.instruction = mulInstruction;
+    mulInstruction->functionReturnReg = &mulResult;
+    list.addInstruction(mulInstruction);
+
+    // Assign final result to variable: var1 = ((5 + 3) * 2)
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &mulResult });
+    list.addInstruction(setVar1);
+
+    // Query position after the assignment
+    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(queryPos);
+
+    // var1 should have Number type from chained operations
+    ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::String), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, InstructionReturnType_QueryBeforeAssignment)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", "");
+
+    // Query position before any operations
+    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(queryPos);
+
+    // Create add instruction: 5 + 3 (after query position)
+    auto addInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Add, nullptr, false);
+    LLVMConstantRegister operand1(Compiler::StaticType::Number, 5);
+    LLVMConstantRegister operand2(Compiler::StaticType::Number, 3);
+    addInstruction->args.push_back({ Compiler::StaticType::Number, &operand1 });
+    addInstruction->args.push_back({ Compiler::StaticType::Number, &operand2 });
+
+    LLVMRegister addResult(Compiler::StaticType::Number);
+    addResult.isRawValue = true;
+    addResult.instruction = addInstruction;
+    addInstruction->functionReturnReg = &addResult;
+    list.addInstruction(addInstruction);
+
+    // Assign add result to variable: var1 = (5 + 3) (after query position)
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &addResult });
+    list.addInstruction(setVar1);
+
+    // var1 should have the previous type since assignment is after query position
+    ASSERT_EQ(analyzer.variableType(&var1, queryPos.get(), Compiler::StaticType::String), Compiler::StaticType::String);
+}
diff --git a/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp b/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp
index dc30be45..c2964dd1 100644
--- a/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp
+++ b/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp
@@ -2289,3 +2289,227 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SelfAssignmentWithTypeChange_Afte
     // Should return number because it's assigned later in the loop
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::String), Compiler::StaticType::Number);
 }
+
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, InstructionReturnType_AddNumbers)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    // Create add instruction: 5 + 3
+    auto addInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Add, nullptr, false);
+    LLVMConstantRegister operand1(Compiler::StaticType::Number, 5);
+    LLVMConstantRegister operand2(Compiler::StaticType::Number, 3);
+    addInstruction->args.push_back({ Compiler::StaticType::Number, &operand1 });
+    addInstruction->args.push_back({ Compiler::StaticType::Number, &operand2 });
+
+    // Set up return register for add instruction
+    LLVMRegister addResult(Compiler::StaticType::Number);
+    addResult.isRawValue = true;
+    addResult.instruction = addInstruction;
+    addInstruction->functionReturnReg = &addResult;
+    list.addInstruction(addInstruction);
+
+    // Assign add result to variable: var1 = (5 + 3)
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &addResult });
+    list.addInstruction(setVar1);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    // var1 should have Number type from add instruction return
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::String), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, InstructionReturnType_StringConcat)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    // Create string concatenation instruction: "hello" + "world"
+    auto concatInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::StringConcat, nullptr, false);
+    LLVMConstantRegister str1(Compiler::StaticType::String, "hello");
+    LLVMConstantRegister str2(Compiler::StaticType::String, "world");
+    concatInstruction->args.push_back({ Compiler::StaticType::String, &str1 });
+    concatInstruction->args.push_back({ Compiler::StaticType::String, &str2 });
+
+    // Set up return register for concat instruction
+    LLVMRegister concatResult(Compiler::StaticType::String);
+    concatResult.isRawValue = true;
+    concatResult.instruction = concatInstruction;
+    concatInstruction->functionReturnReg = &concatResult;
+    list.addInstruction(concatInstruction);
+
+    // Assign concat result to variable: var1 = ("hello" + "world")
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &concatResult });
+    list.addInstruction(setVar1);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    // var1 should have String type from concat instruction return
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, InstructionReturnType_MathFunction)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    // Create sqrt instruction: sqrt(16)
+    auto sqrtInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Sqrt, nullptr, false);
+    LLVMConstantRegister operand(Compiler::StaticType::Number, 16);
+    sqrtInstruction->args.push_back({ Compiler::StaticType::Number, &operand });
+
+    // Set up return register for sqrt instruction
+    LLVMRegister sqrtResult(Compiler::StaticType::Number);
+    sqrtResult.isRawValue = true;
+    sqrtResult.instruction = sqrtInstruction;
+    sqrtInstruction->functionReturnReg = &sqrtResult;
+    list.addInstruction(sqrtInstruction);
+
+    // Assign sqrt result to variable: var1 = sqrt(16)
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &sqrtResult });
+    list.addInstruction(setVar1);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    // var1 should have Number type from sqrt instruction return
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::String), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, InstructionReturnType_Comparison)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    // Create comparison instruction: 5 > 3
+    auto cmpInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::CmpGT, nullptr, false);
+    LLVMConstantRegister operand1(Compiler::StaticType::Number, 5);
+    LLVMConstantRegister operand2(Compiler::StaticType::Number, 3);
+    cmpInstruction->args.push_back({ Compiler::StaticType::Number, &operand1 });
+    cmpInstruction->args.push_back({ Compiler::StaticType::Number, &operand2 });
+
+    // Set up return register for comparison instruction
+    LLVMRegister cmpResult(Compiler::StaticType::Bool);
+    cmpResult.isRawValue = true;
+    cmpResult.instruction = cmpInstruction;
+    cmpInstruction->functionReturnReg = &cmpResult;
+    list.addInstruction(cmpInstruction);
+
+    // Assign comparison result to variable: var1 = (5 > 3)
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &cmpResult });
+    list.addInstruction(setVar1);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    // var1 should have Bool type from comparison instruction return
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Bool);
+}
+
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, InstructionReturnType_FunctionCall)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    // Create function call instruction
+    auto funcInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    funcInstruction->functionName = "some_reporter_function";
+    LLVMConstantRegister arg(Compiler::StaticType::Number, 42);
+    funcInstruction->args.push_back({ Compiler::StaticType::Number, &arg });
+
+    // Set up return register for function call
+    LLVMRegister funcResult(Compiler::StaticType::String);
+    funcResult.isRawValue = true;
+    funcResult.instruction = funcInstruction;
+    funcInstruction->functionReturnReg = &funcResult;
+    list.addInstruction(funcInstruction);
+
+    // Assign function result to variable: var1 = some_reporter_function(42)
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &funcResult });
+    list.addInstruction(setVar1);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    // var1 should have String type from function call return
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, InstructionReturnType_ChainedOperations)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var1("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    // First operation: 5 + 3
+    auto addInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Add, nullptr, false);
+    LLVMConstantRegister operand1(Compiler::StaticType::Number, 5);
+    LLVMConstantRegister operand2(Compiler::StaticType::Number, 3);
+    addInstruction->args.push_back({ Compiler::StaticType::Number, &operand1 });
+    addInstruction->args.push_back({ Compiler::StaticType::Number, &operand2 });
+
+    LLVMRegister addResult(Compiler::StaticType::Number);
+    addResult.isRawValue = true;
+    addResult.instruction = addInstruction;
+    addInstruction->functionReturnReg = &addResult;
+    list.addInstruction(addInstruction);
+
+    // Second operation: (5 + 3) * 2
+    auto mulInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Mul, nullptr, false);
+    LLVMConstantRegister multiplier(Compiler::StaticType::Number, 2);
+    mulInstruction->args.push_back({ Compiler::StaticType::Unknown, &addResult });
+    mulInstruction->args.push_back({ Compiler::StaticType::Number, &multiplier });
+
+    LLVMRegister mulResult(Compiler::StaticType::Number);
+    mulResult.isRawValue = true;
+    mulResult.instruction = mulInstruction;
+    mulInstruction->functionReturnReg = &mulResult;
+    list.addInstruction(mulInstruction);
+
+    // Assign final result to variable: var1 = ((5 + 3) * 2)
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    setVar1->workVariable = &var1;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &mulResult });
+    list.addInstruction(setVar1);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    // var1 should have Number type from chained operations
+    ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::String), Compiler::StaticType::Number);
+}

From 547c5066711a86c94b7b4097e1efc8cdf98ac536 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Sun, 27 Jul 2025 14:09:22 +0200
Subject: [PATCH 37/79] LLVMTypeAnalyzer: Move find branch end logic to
 branchEnd()

---
 src/engine/internal/llvm/llvmtypeanalyzer.cpp | 47 +++++++++++--------
 src/engine/internal/llvm/llvmtypeanalyzer.h   |  1 +
 2 files changed, 28 insertions(+), 20 deletions(-)

diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
index aace9e48..487dd88d 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
@@ -107,31 +107,14 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(Variable *var, LL
     if (!var || !start)
         return previousType;
 
-    assert(isLoopStart(start) || isIfStart(start) || isElse(start));
-
-    // Find loop/if statement end or else branch
-    LLVMInstruction *ins = start->next;
-    int level = 0;
+    LLVMInstruction *end = branchEnd(start);
 
-    while (ins && !((isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) && level == 0)) {
-        if (isLoopStart(ins) || isIfStart(ins))
-            level++;
-        else if (isLoopEnd(ins) || isIfEnd(ins)) {
-            assert(level > 0);
-            level--;
-        }
-
-        ins = ins->next;
-    }
-
-    if (!ins) {
-        assert(false);
+    if (!end)
         return Compiler::StaticType::Unknown;
-    }
 
     // Process the branch from end
     bool write = false; // only used internally (the compiler doesn't need this)
-    return variableTypeAfterBranchFromEnd(var, ins, previousType, write, visitedInstructions);
+    return variableTypeAfterBranchFromEnd(var, end, previousType, write, visitedInstructions);
 }
 
 Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable *var, LLVMInstruction *end, Compiler::StaticType previousType, bool &write, InstructionSet &visitedInstructions) const
@@ -187,6 +170,30 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable *
     return previousType;
 }
 
+LLVMInstruction *LLVMTypeAnalyzer::branchEnd(LLVMInstruction *start) const
+{
+    assert(start);
+    assert(isLoopStart(start) || isIfStart(start) || isElse(start));
+
+    // Find loop/if statement end or else branch
+    LLVMInstruction *ins = start->next;
+    int level = 0;
+
+    while (ins && !((isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) && level == 0)) {
+        if (isLoopStart(ins) || isIfStart(ins))
+            level++;
+        else if (isLoopEnd(ins) || isIfEnd(ins)) {
+            assert(level > 0);
+            level--;
+        }
+
+        ins = ins->next;
+    }
+
+    assert(ins);
+    return ins;
+}
+
 LLVMInstruction *LLVMTypeAnalyzer::skipBranch(LLVMInstruction *pos) const
 {
     int level = 0;
diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.h b/src/engine/internal/llvm/llvmtypeanalyzer.h
index ac32565b..f3bd20d1 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.h
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.h
@@ -21,6 +21,7 @@ class LLVMTypeAnalyzer
         Compiler::StaticType variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const;
         Compiler::StaticType variableTypeAfterBranchFromEnd(Variable *var, LLVMInstruction *end, Compiler::StaticType previousType, bool &write, InstructionSet &visitedInstructions) const;
 
+        LLVMInstruction *branchEnd(LLVMInstruction *start) const;
         LLVMInstruction *skipBranch(LLVMInstruction *pos) const;
 
         bool isLoopStart(LLVMInstruction *ins) const;

From 005357a0a8087479cba03168e6130d81b79eb4fa Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Sun, 27 Jul 2025 14:14:20 +0200
Subject: [PATCH 38/79] LLVMTypeAnalyzer: skipBranch() -> branchStart()

---
 src/engine/internal/llvm/llvmtypeanalyzer.cpp | 28 +++++++++++--------
 src/engine/internal/llvm/llvmtypeanalyzer.h   |  2 +-
 2 files changed, 17 insertions(+), 13 deletions(-)

diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
index 487dd88d..877ce84b 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
@@ -62,7 +62,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstructi
         } else if (isElse(ins)) {
             // Skip if branch if coming from else
             firstElseBranch = ins;
-            ins = skipBranch(ins);
+            ins = branchStart(ins);
             continue;
         } else if (isVariableWrite(ins, var) && !isWriteNoOp(ins)) {
             if (level <= 0) { // ignore nested branches (they're handled by the branch analyzer)
@@ -134,7 +134,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable *
             } else
                 return Compiler::StaticType::Unknown;
 
-            ins = skipBranch(ins);
+            ins = branchStart(ins);
 
             if (isElse(ins)) {
                 // Process if branch (the else branch is already processed)
@@ -150,7 +150,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable *
                 } else
                     return Compiler::StaticType::Unknown;
 
-                ins = skipBranch(ins);
+                ins = branchStart(ins);
             }
         } else if (isVariableWrite(ins, var) && !isWriteNoOp(ins)) {
             // Variable write instruction
@@ -194,29 +194,33 @@ LLVMInstruction *LLVMTypeAnalyzer::branchEnd(LLVMInstruction *start) const
     return ins;
 }
 
-LLVMInstruction *LLVMTypeAnalyzer::skipBranch(LLVMInstruction *pos) const
+LLVMInstruction *LLVMTypeAnalyzer::branchStart(LLVMInstruction *end) const
 {
+    assert(end);
+    assert(isLoopEnd(end) || isIfEnd(end) || isElse(end));
+
+    // Find loop/if statement/else branch start
+    LLVMInstruction *ins = end->previous;
     int level = 0;
-    pos = pos->previous;
 
-    while (pos && !((isLoopStart(pos) || isIfStart(pos)) && level == 0)) {
-        if (isLoopStart(pos) || isIfStart(pos)) {
+    while (ins && !((isLoopStart(ins) || isIfStart(ins)) && level == 0)) {
+        if (isLoopStart(ins) || isIfStart(ins)) {
             assert(level > 0);
             level--;
         }
 
-        if (isLoopEnd(pos) || isIfEnd(pos) || isElse(pos)) {
-            if (isElse(pos) && level == 0)
+        if (isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) {
+            if (isElse(ins) && level == 0)
                 break;
 
             level++;
         }
 
-        pos = pos->previous;
+        ins = ins->previous;
     };
 
-    assert(pos);
-    return pos;
+    assert(ins);
+    return ins;
 }
 
 bool LLVMTypeAnalyzer::isLoopStart(LLVMInstruction *ins) const
diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.h b/src/engine/internal/llvm/llvmtypeanalyzer.h
index f3bd20d1..ed7320a7 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.h
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.h
@@ -22,7 +22,7 @@ class LLVMTypeAnalyzer
         Compiler::StaticType variableTypeAfterBranchFromEnd(Variable *var, LLVMInstruction *end, Compiler::StaticType previousType, bool &write, InstructionSet &visitedInstructions) const;
 
         LLVMInstruction *branchEnd(LLVMInstruction *start) const;
-        LLVMInstruction *skipBranch(LLVMInstruction *pos) const;
+        LLVMInstruction *branchStart(LLVMInstruction *end) const;
 
         bool isLoopStart(LLVMInstruction *ins) const;
         bool isLoopEnd(LLVMInstruction *ins) const;

From c9342a9350577c83eb1da22da233ec5b1554c203 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Sun, 27 Jul 2025 15:21:48 +0200
Subject: [PATCH 39/79] LLVMTypeAnalyzer: Implement listTypeAfterBranch() for
 basic cases

---
 src/engine/internal/llvm/llvmtypeanalyzer.cpp |   69 +
 src/engine/internal/llvm/llvmtypeanalyzer.h   |    5 +
 test/llvm/CMakeLists.txt                      |    1 +
 .../listtypeafterbranch_test.cpp              | 1670 +++++++++++++++++
 4 files changed, 1745 insertions(+)
 create mode 100644 test/llvm/type_analyzer/listtypeafterbranch_test.cpp

diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
index 877ce84b..b4ccebb1 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
@@ -8,6 +8,8 @@ using namespace libscratchcpp;
 static const std::unordered_set<LLVMInstruction::Type>
     BEGIN_LOOP_INSTRUCTIONS = { LLVMInstruction::Type::BeginRepeatLoop, LLVMInstruction::Type::BeginWhileLoop, LLVMInstruction::Type::BeginRepeatUntilLoop };
 
+static const std::unordered_set<LLVMInstruction::Type> LIST_WRITE_INSTRUCTIONS = { LLVMInstruction::Type::AppendToList, LLVMInstruction::Type::InsertToList, LLVMInstruction::Type::ListReplace };
+
 Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType) const
 {
     InstructionSet visitedInstructions;
@@ -20,6 +22,68 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(Variable *var, LL
     return variableTypeAfterBranch(var, start, previousType, visitedInstructions);
 }
 
+Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch(List *list, LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty) const
+{
+    if (!list || !start)
+        return previousType;
+
+    assert(isLoopStart(start) || isIfStart(start) || isElse(start));
+
+    InstructionSet visitedInstructions; // TODO: Handle cross-variable/list dependencies
+
+    LLVMInstruction *ins = start->next;
+    LLVMInstruction *lastWrite = nullptr;
+    Compiler::StaticType lastWriteType = Compiler::StaticType::Unknown;
+    int level = 0;
+
+    while (ins && !((isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) && level == 0)) {
+        if (isLoopStart(ins) || isIfStart(ins))
+            level++;
+        else if (isLoopEnd(ins) || isIfEnd(ins)) {
+            assert(level > 0);
+            level--;
+        } else if (isListWrite(ins, list)) {
+            // List write instruction
+            Compiler::StaticType writeType = writeValueType(ins, visitedInstructions);
+
+            // For non-empty lists, we can just check the write type
+            if (!isEmpty && !typesMatch(writeType, previousType)) {
+                return Compiler::StaticType::Unknown;
+            }
+
+            // In empty lists, writes of the same type determine the final type
+            if (isEmpty) {
+                if (lastWrite) {
+                    // There was a write before which means it might determine the final type
+                    if (!typesMatch(writeType, lastWriteType))
+                        return Compiler::StaticType::Unknown;
+                } else {
+                    // This is the first write found, it might determine the final type
+                    lastWrite = ins;
+                    lastWriteType = writeType;
+                }
+            }
+        }
+
+        ins = ins->next;
+    }
+
+    assert(ins);
+
+    if (isEmpty) {
+        if (lastWrite) {
+            // Only writes of the same type modify the list
+            return lastWriteType;
+        } else {
+            // No writes to empty list found, keep the previous type
+            return previousType;
+        }
+    } else {
+        // No type conflicts found for non-empty list
+        return previousType;
+    }
+}
+
 Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const
 {
     if (!var || !pos)
@@ -258,6 +322,11 @@ bool LLVMTypeAnalyzer::isVariableWrite(LLVMInstruction *ins, Variable *var) cons
     return (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == var);
 }
 
+bool LLVMTypeAnalyzer::isListWrite(LLVMInstruction *ins, List *list) const
+{
+    return (LIST_WRITE_INSTRUCTIONS.find(ins->type) != LIST_WRITE_INSTRUCTIONS.cend() && ins->workList == list);
+}
+
 Compiler::StaticType LLVMTypeAnalyzer::optimizeRegisterType(LLVMRegister *reg) const
 {
     // TODO: Move this method out if it's used in LLVMCodeBuilder too
diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.h b/src/engine/internal/llvm/llvmtypeanalyzer.h
index ed7320a7..046b29b8 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.h
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.h
@@ -14,6 +14,8 @@ class LLVMTypeAnalyzer
         Compiler::StaticType variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType) const;
         Compiler::StaticType variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType) const;
 
+        Compiler::StaticType listTypeAfterBranch(List *list, LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty) const;
+
     private:
         using InstructionSet = std::unordered_set<LLVMInstruction *>;
 
@@ -29,9 +31,12 @@ class LLVMTypeAnalyzer
         bool isIfStart(LLVMInstruction *ins) const;
         bool isElse(LLVMInstruction *ins) const;
         bool isIfEnd(LLVMInstruction *ins) const;
+
         bool isVariableRead(LLVMInstruction *ins) const;
         bool isVariableWrite(LLVMInstruction *ins, Variable *var) const;
 
+        bool isListWrite(LLVMInstruction *ins, List *list) const;
+
         Compiler::StaticType optimizeRegisterType(LLVMRegister *reg) const;
         bool isWriteNoOp(LLVMInstruction *ins) const;
         Compiler::StaticType writeValueType(LLVMInstruction *ins, InstructionSet &visitedInstructions) const;
diff --git a/test/llvm/CMakeLists.txt b/test/llvm/CMakeLists.txt
index 0ba3385a..e1d005cc 100644
--- a/test/llvm/CMakeLists.txt
+++ b/test/llvm/CMakeLists.txt
@@ -22,6 +22,7 @@ add_executable(
   llvminstructionlist_test.cpp
   type_analyzer/variabletypeafterbranch_test.cpp
   type_analyzer/variabletype_test.cpp
+  type_analyzer/listtypeafterbranch_test.cpp
 )
 
 target_link_libraries(
diff --git a/test/llvm/type_analyzer/listtypeafterbranch_test.cpp b/test/llvm/type_analyzer/listtypeafterbranch_test.cpp
new file mode 100644
index 00000000..80d6258b
--- /dev/null
+++ b/test/llvm/type_analyzer/listtypeafterbranch_test.cpp
@@ -0,0 +1,1670 @@
+#include <scratchcpp/list.h>
+#include <engine/internal/llvm/llvmtypeanalyzer.h>
+#include <engine/internal/llvm/llvminstruction.h>
+#include <engine/internal/llvm/llvminstructionlist.h>
+#include <engine/internal/llvm/llvmconstantregister.h>
+#include <gtest/gtest.h>
+
+using namespace libscratchcpp;
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, NullParams)
+{
+    LLVMTypeAnalyzer analyzer;
+    ASSERT_EQ(analyzer.listTypeAfterBranch(nullptr, nullptr, Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, NullList)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(start);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(nullptr, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, NullStartInstruction)
+{
+    LLVMTypeAnalyzer analyzer;
+    List list("", "");
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, nullptr, Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, EmptyLoop)
+{
+    LLVMTypeAnalyzer analyzer;
+    List list("", "");
+    LLVMInstructionList instructionList;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, EmptyIfStatement)
+{
+    LLVMTypeAnalyzer analyzer;
+    List list("", "");
+    LLVMInstructionList instructionList;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, EmptyIfElseStatement_IfBranch)
+{
+    LLVMTypeAnalyzer analyzer;
+    List list("", "");
+    LLVMInstructionList instructionList;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, EmptyIfElseStatement_ElseBranch)
+{
+    LLVMTypeAnalyzer analyzer;
+    List list("", "");
+    LLVMInstructionList instructionList;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, elseStart.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, EmptyLoopUnknownType)
+{
+    LLVMTypeAnalyzer analyzer;
+    List list("", "");
+    LLVMInstructionList instructionList;
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Unknown, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, NoWriteOperations)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendSameTypeNumber)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 1.25);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendSameTypeBool)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Bool, true);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Bool, false), Compiler::StaticType::Bool);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendSameTypeString)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, false), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendStringOptimization)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "1.25");
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Although string is appended, it's constant and represents a number
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendMultipleLists)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list1("", "");
+    List list2("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // Append to list1
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 6);
+    appendList1->workList = &list1;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Append to list2
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    appendList2->workList = &list2;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list1, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendFromUnknownType)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMRegister value(Compiler::StaticType::Unknown);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendToUnknownType)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 5);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Unknown, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendUnknownToUnknownType)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMRegister value(Compiler::StaticType::Unknown);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Unknown, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleInsertSameType)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    LLVMConstantRegister index(Compiler::StaticType::Number, 1);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Number, &index });
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, false), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleReplaceSameType)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    LLVMConstantRegister index(Compiler::StaticType::Number, 1);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Number, &index });
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, false), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeNumberToString_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeNumberToString_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeStringToNumber_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 5.8);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, true), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeStringToNumber_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 5.8);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeNumberToBool_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Bool, true);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Bool);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeNumberToBool_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Bool, true);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeBoolToNumber_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 1);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Bool, true), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeBoolToNumber_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 1);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Bool, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeBoolToString_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "abc");
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Bool, true), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeBoolToString_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "abc");
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Bool, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeStringToBool_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Bool, false);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, true), Compiler::StaticType::Bool);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeStringToBool_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Bool, false);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendSameType_IfStatement)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 1.25);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentType_IfStatement_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 5.8);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, true), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentType_IfStatement_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 5.8);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleInsertDifferentType_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    LLVMConstantRegister index(Compiler::StaticType::Number, 1);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Number, &index });
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Insert might be a no-op depending on the index
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleInsertDifferentType_Empty_UnknownType)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    LLVMConstantRegister index(Compiler::StaticType::Number, 1);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Number, &index });
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Insert might be a no-op depending on the index
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Unknown, true), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleInsertDifferentType_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    LLVMConstantRegister index(Compiler::StaticType::Number, 1);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Number, &index });
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleReplaceDifferentType_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    LLVMConstantRegister index(Compiler::StaticType::Number, 1);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Number, &index });
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Since the list is empty, it's safe to return any type
+    // Let's return string in this case as the replace instruction indicates that string is used later
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleReplaceDifferentType_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    LLVMConstantRegister index(Compiler::StaticType::Number, 1);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Number, &index });
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleAppendsDifferentTypes_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // First append: string "abc" (incompatible with Number)
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "abc");
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Second append: number 5.25 (compatible with Number pre-loop type)
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 5.25);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Should return Unknown because first append creates type conflict with pre-loop Number type
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleAppendsDifferentTypes_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // First append: string "abc" (incompatible with Number)
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "abc");
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Second append: number 5.25 (compatible with Number pre-loop type)
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 5.25);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Should return Unknown because first append creates type conflict with pre-loop Number type
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleAppendsWithStringOptimization)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // First append: number 2 (compatible with Number)
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 2);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Second append: string "3.14" (optimized to Number, compatible with pre-loop type)
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "3.14");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Should return Number because final append is optimized to Number type
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleAppendsDifferentTypes_IfStatement)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // First append: string "abc" (incompatible with Number)
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "abc");
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Second append: number 5.25 (compatible with Number type)
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 5.25);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Should return Unknown because first append creates type conflict with Number type
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleAppendsDifferentTypes_IfBranch)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // First append: string "abc" (incompatible with Number)
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "abc");
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Second append: number 5.25 (compatible with Number type)
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 5.25);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    // Else branch append: string "test" (incompatible with Number type)
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value3(Compiler::StaticType::String, "test");
+    appendList3->workList = &list;
+    appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    instructionList.addInstruction(appendList3);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Should return Unknown because first append in if branch creates type conflict
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleAppendsSameType_ElseBranch)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // First append: string "abc" (incompatible with Number)
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "abc");
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    // Else branch first append: string "abc" (incompatible with Number)
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "abc");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    // Else branch second append: number 5.25 (compatible with Number type)
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value3(Compiler::StaticType::Number, 5.25);
+    appendList3->workList = &list;
+    appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    instructionList.addInstruction(appendList3);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Should return Unknown because first append in else branch creates type conflict
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, elseStart.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, IfStatementInLoop_TypeChangeInIfBranch)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // First append - changes type
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "test");
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    // Second append - does not change type
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 42);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Returns unknown type because the type-changing branch might or might not run
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, IfStatementInLoop_TypeChangeInElseBranch)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // First append - does not change type
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    // Second append - changes type
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Returns unknown type because the type-changing branch might or might not run
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, IfStatementInLoop_IfElseWithoutTypeChange)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // First append - does not change type
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    // Second append - does not change type
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleInsertsDifferentTypes)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // First insert: number
+    auto insertList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    LLVMConstantRegister index1(Compiler::StaticType::Number, 1);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
+    insertList1->workList = &list;
+    insertList1->args.push_back({ Compiler::StaticType::Number, &index1 });
+    insertList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(insertList1);
+
+    // Second insert: string (creates type conflict)
+    auto insertList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    LLVMConstantRegister index2(Compiler::StaticType::Number, 1);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    insertList2->workList = &list;
+    insertList2->args.push_back({ Compiler::StaticType::Number, &index2 });
+    insertList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(insertList2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleReplacesDifferentTypes)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // First replace: compatible with Bool
+    auto replaceList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    LLVMConstantRegister index1(Compiler::StaticType::Number, 1);
+    LLVMConstantRegister value1(Compiler::StaticType::Bool, true);
+    replaceList1->workList = &list;
+    replaceList1->args.push_back({ Compiler::StaticType::Number, &index1 });
+    replaceList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(replaceList1);
+
+    // Second replace: incompatible with Bool
+    auto replaceList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    LLVMConstantRegister index2(Compiler::StaticType::Number, 2);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    replaceList2->workList = &list;
+    replaceList2->args.push_back({ Compiler::StaticType::Number, &index2 });
+    replaceList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(replaceList2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Bool, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CombinedAppendInsertReplace_SameTypes)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // First: append number (compatible with Number)
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister appendValue(Compiler::StaticType::Number, 42);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &appendValue });
+    instructionList.addInstruction(appendList);
+
+    // Second: insert number (compatible with Number)
+    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    LLVMConstantRegister insertIndex(Compiler::StaticType::Number, 1);
+    LLVMConstantRegister insertValue(Compiler::StaticType::Number, 5);
+    insertList->workList = &list;
+    insertList->args.push_back({ Compiler::StaticType::Number, &insertIndex });
+    insertList->args.push_back({ Compiler::StaticType::Unknown, &insertValue });
+    instructionList.addInstruction(insertList);
+
+    // Third: replace with number (compatible with Number)
+    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    LLVMConstantRegister replaceIndex(Compiler::StaticType::Number, 2);
+    LLVMConstantRegister replaceValue(Compiler::StaticType::Number, 3.14);
+    replaceList->workList = &list;
+    replaceList->args.push_back({ Compiler::StaticType::Number, &replaceIndex });
+    replaceList->args.push_back({ Compiler::StaticType::Unknown, &replaceValue });
+    instructionList.addInstruction(replaceList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Should return Number because only numbers are used
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CombinedAppendInsertReplace_TypeConflict)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // First: append number (compatible with Number)
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister appendValue(Compiler::StaticType::Number, 42);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &appendValue });
+    instructionList.addInstruction(appendList);
+
+    // Second: insert string (creates type conflict)
+    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    LLVMConstantRegister insertIndex(Compiler::StaticType::Number, 0);
+    LLVMConstantRegister insertValue(Compiler::StaticType::String, "hello");
+    insertList->workList = &list;
+    insertList->args.push_back({ Compiler::StaticType::Number, &insertIndex });
+    insertList->args.push_back({ Compiler::StaticType::Unknown, &insertValue });
+    instructionList.addInstruction(insertList);
+
+    // Third: replace with number (still conflicted)
+    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    LLVMConstantRegister replaceIndex(Compiler::StaticType::Number, 1);
+    LLVMConstantRegister replaceValue(Compiler::StaticType::Number, 3.14);
+    replaceList->workList = &list;
+    replaceList->args.push_back({ Compiler::StaticType::Number, &replaceIndex });
+    replaceList->args.push_back({ Compiler::StaticType::Unknown, &replaceValue });
+    instructionList.addInstruction(replaceList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Should return Unknown because insert created type conflict
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, NestedLoopWithTypeChange)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(outerLoop);
+
+    // List append inside outer loop
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Inner loop begin
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(innerLoop);
+
+    // List append inside inner loop (creates type conflict)
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    // Inner loop end
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(innerEnd);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(outerEnd);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, outerLoop.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, NestedLoopWithoutTypeChange)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginWhileLoop, nullptr, false);
+    instructionList.addInstruction(outerLoop);
+
+    // List append inside outer loop
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Inner loop begin
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(innerLoop);
+
+    // List append inside inner loop (same type)
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 2.5);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    // Inner loop end
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(innerEnd);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(outerEnd);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, outerLoop.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, NestedLoopWithTypeChangeBeforeLoop)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false);
+    instructionList.addInstruction(outerLoop);
+
+    // List append inside outer loop (creates type conflict)
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "test");
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Inner loop begin
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(innerLoop);
+
+    // List append inside inner loop
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 5);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    // Inner loop end
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(innerEnd);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(outerEnd);
+
+    // Returns unknown type because first append creates type conflict
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, outerLoop.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, IfStatementInLoopWithTypeChangeBeforeLoop_TypeChangeInIfBranch)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false);
+    instructionList.addInstruction(outerLoop);
+
+    // List append inside outer loop (creates type conflict)
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "test");
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Inner if statement begin
+    auto innerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(innerIf);
+
+    // List append inside inner if statement if branch
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 5);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    // Inner if statement else branch begin
+    auto innerElse = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(innerElse);
+
+    // Inner if statement end
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(innerEnd);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(outerEnd);
+
+    // Returns unknown type because first append already created type conflict
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, outerLoop.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleNestedLoopsWithTypeChange)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(outerLoop);
+
+    // List append inside outer loop
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Inner loop 1 begin
+    auto innerLoop1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(innerLoop1);
+
+    // List append inside inner loop 1
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    // Inner loop 2 begin
+    auto innerLoop2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(innerLoop2);
+
+    // List append inside inner loop 2 (creates type conflict)
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value3(Compiler::StaticType::String, "abc");
+    appendList3->workList = &list;
+    appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    instructionList.addInstruction(appendList3);
+
+    // Inner loop 2 end
+    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(innerEnd2);
+
+    // Inner loop 1 end
+    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(innerEnd1);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(outerEnd);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, outerLoop.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleNestedIfStatementsWithTypeChange_IfBranch)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // Outer if statement begin
+    auto outerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(outerIf);
+
+    // List append inside outer if statement
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Inner if statement 1 begin
+    auto innerIf1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(innerIf1);
+
+    // List append inside inner if statement 1
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    // Inner if statement 2 begin
+    auto innerIf2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(innerIf2);
+
+    // List append inside inner if statement 2 (creates type conflict)
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value3(Compiler::StaticType::String, "abc");
+    appendList3->workList = &list;
+    appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    instructionList.addInstruction(appendList3);
+
+    // Inner if statement 2 else branch
+    auto innerElse2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(innerElse2);
+
+    // List append inside inner if statement 2 else branch
+    auto appendList4 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value4(Compiler::StaticType::Number, 4);
+    appendList4->workList = &list;
+    appendList4->args.push_back({ Compiler::StaticType::Unknown, &value4 });
+    instructionList.addInstruction(appendList4);
+
+    // Inner if statement 2 end
+    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(innerEnd2);
+
+    // Inner if statement 1 end
+    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(innerEnd1);
+
+    // Outer if statement end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(outerEnd);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, outerIf.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleNestedIfStatementsWithTypeChange_ElseBranch)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // Outer if statement begin
+    auto outerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(outerIf);
+
+    // List append inside outer if statement
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Inner if statement 1 begin
+    auto innerIf1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(innerIf1);
+
+    // List append inside inner if statement 1
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    // Inner if statement 2 begin
+    auto innerIf2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(innerIf2);
+
+    // List append inside inner if statement 2
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value3(Compiler::StaticType::Number, 4);
+    appendList3->workList = &list;
+    appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    instructionList.addInstruction(appendList3);
+
+    // Inner if statement 2 else branch
+    auto innerElse2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(innerElse2);
+
+    // List append inside inner if statement 2 else branch (creates type conflict)
+    auto appendList4 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value4(Compiler::StaticType::String, "abc");
+    appendList4->workList = &list;
+    appendList4->args.push_back({ Compiler::StaticType::Unknown, &value4 });
+    instructionList.addInstruction(appendList4);
+
+    // Inner if statement 2 end
+    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(innerEnd2);
+
+    // Inner if statement 1 end
+    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(innerEnd1);
+
+    // Outer if statement end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(outerEnd);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, outerIf.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleNestedIfStatementsWithoutTypeChange)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // Outer if statement begin
+    auto outerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(outerIf);
+
+    // List append inside outer if statement
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Inner if statement 1 begin
+    auto innerIf1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(innerIf1);
+
+    // List append inside inner if statement 1
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    // Inner if statement 2 begin
+    auto innerIf2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(innerIf2);
+
+    // List append inside inner if statement 2
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value3(Compiler::StaticType::Number, 4);
+    appendList3->workList = &list;
+    appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    instructionList.addInstruction(appendList3);
+
+    // Inner if statement 2 else branch
+    auto innerElse2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(innerElse2);
+
+    // List append inside inner if statement 2 else branch (same type)
+    auto appendList4 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value4(Compiler::StaticType::Number, 0);
+    appendList4->workList = &list;
+    appendList4->args.push_back({ Compiler::StaticType::Unknown, &value4 });
+    instructionList.addInstruction(appendList4);
+
+    // Inner if statement 2 end
+    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(innerEnd2);
+
+    // Inner if statement 1 end
+    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(innerEnd1);
+
+    // Outer if statement end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(outerEnd);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, outerIf.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}

From f9afdfc63123ebfc0d54d4199a274c05c6f07660 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Wed, 30 Jul 2025 12:19:43 +0200
Subject: [PATCH 40/79] LLVMTypeAnalyzer: Handle list clear instruction

---
 src/engine/internal/llvm/llvmtypeanalyzer.cpp | 112 +--
 src/engine/internal/llvm/llvmtypeanalyzer.h   |   2 +
 .../listtypeafterbranch_test.cpp              | 703 ++++++++++++++++++
 3 files changed, 762 insertions(+), 55 deletions(-)

diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
index b4ccebb1..b80fa7f6 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
@@ -27,61 +27,8 @@ Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch(List *list, LLVMInstr
     if (!list || !start)
         return previousType;
 
-    assert(isLoopStart(start) || isIfStart(start) || isElse(start));
-
-    InstructionSet visitedInstructions; // TODO: Handle cross-variable/list dependencies
-
-    LLVMInstruction *ins = start->next;
-    LLVMInstruction *lastWrite = nullptr;
-    Compiler::StaticType lastWriteType = Compiler::StaticType::Unknown;
-    int level = 0;
-
-    while (ins && !((isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) && level == 0)) {
-        if (isLoopStart(ins) || isIfStart(ins))
-            level++;
-        else if (isLoopEnd(ins) || isIfEnd(ins)) {
-            assert(level > 0);
-            level--;
-        } else if (isListWrite(ins, list)) {
-            // List write instruction
-            Compiler::StaticType writeType = writeValueType(ins, visitedInstructions);
-
-            // For non-empty lists, we can just check the write type
-            if (!isEmpty && !typesMatch(writeType, previousType)) {
-                return Compiler::StaticType::Unknown;
-            }
-
-            // In empty lists, writes of the same type determine the final type
-            if (isEmpty) {
-                if (lastWrite) {
-                    // There was a write before which means it might determine the final type
-                    if (!typesMatch(writeType, lastWriteType))
-                        return Compiler::StaticType::Unknown;
-                } else {
-                    // This is the first write found, it might determine the final type
-                    lastWrite = ins;
-                    lastWriteType = writeType;
-                }
-            }
-        }
-
-        ins = ins->next;
-    }
-
-    assert(ins);
-
-    if (isEmpty) {
-        if (lastWrite) {
-            // Only writes of the same type modify the list
-            return lastWriteType;
-        } else {
-            // No writes to empty list found, keep the previous type
-            return previousType;
-        }
-    } else {
-        // No type conflicts found for non-empty list
-        return previousType;
-    }
+    bool write = false; // only used internally (the compiler doesn't need this)
+    return listTypeAfterBranch(list, start, previousType, isEmpty, write);
 }
 
 Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const
@@ -234,6 +181,61 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable *
     return previousType;
 }
 
+Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch(List *list, LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty, bool &write) const
+{
+    assert(isLoopStart(start) || isIfStart(start) || isElse(start));
+
+    InstructionSet visitedInstructions; // TODO: Handle cross-variable/list dependencies
+
+    LLVMInstruction *ins = start->next;
+    write = false;
+
+    while (ins && !(isLoopEnd(ins) || isIfEnd(ins) || isElse(ins))) {
+        if (isLoopStart(ins) || isIfStart(ins)) {
+            do {
+                Compiler::StaticType type = listTypeAfterBranch(list, ins, previousType, isEmpty, write);
+
+                // If there was a write, the list is no longer empty
+                if (write) {
+                    isEmpty = false;
+
+                    // The write could change the type
+                    if (!typesMatch(type, previousType))
+                        return Compiler::StaticType::Unknown;
+                }
+
+                // Skip the branch
+                ins = branchEnd(ins);
+            } while (isElse(ins)); // handle else branch
+        } else if (isListWrite(ins, list)) {
+            // List write instruction
+            Compiler::StaticType writeType = writeValueType(ins, visitedInstructions);
+            write = true;
+
+            if (isEmpty) {
+                // In empty lists, writes of the same type determine the final type
+                // This is the first write found, it might determine the final type
+                previousType = writeType;
+
+                // The list is no longer empty
+                isEmpty = false;
+            } else if (!typesMatch(writeType, previousType)) {
+                // For non-empty lists, we can just check the write type
+                return Compiler::StaticType::Unknown;
+            }
+        } else if (ins->type == LLVMInstruction::Type::ClearList && ins->workList == list) {
+            // The list is now empty
+            isEmpty = true;
+            write = false; // the write variable is only used to check if the list is still empty
+        }
+
+        ins = ins->next;
+    }
+
+    assert(ins);
+    return previousType;
+}
+
 LLVMInstruction *LLVMTypeAnalyzer::branchEnd(LLVMInstruction *start) const
 {
     assert(start);
diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.h b/src/engine/internal/llvm/llvmtypeanalyzer.h
index 046b29b8..187470a3 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.h
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.h
@@ -23,6 +23,8 @@ class LLVMTypeAnalyzer
         Compiler::StaticType variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const;
         Compiler::StaticType variableTypeAfterBranchFromEnd(Variable *var, LLVMInstruction *end, Compiler::StaticType previousType, bool &write, InstructionSet &visitedInstructions) const;
 
+        Compiler::StaticType listTypeAfterBranch(List *list, LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty, bool &write) const;
+
         LLVMInstruction *branchEnd(LLVMInstruction *start) const;
         LLVMInstruction *branchStart(LLVMInstruction *end) const;
 
diff --git a/test/llvm/type_analyzer/listtypeafterbranch_test.cpp b/test/llvm/type_analyzer/listtypeafterbranch_test.cpp
index 80d6258b..8169e875 100644
--- a/test/llvm/type_analyzer/listtypeafterbranch_test.cpp
+++ b/test/llvm/type_analyzer/listtypeafterbranch_test.cpp
@@ -1668,3 +1668,706 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleNestedIfStatementsWithoutType
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, outerIf.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
 }
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, AppendToEmptyListInIfBranch)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // Append in if branch
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    // Append after if statement - the list might not be empty anymore
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Should return Unknown because the list might not be empty when the type changes
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, AppendToEmptyListInElseBranch)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    // Append in else branch
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    // Append after if statement - the list might not be empty anymore
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Should return Unknown because the list might not be empty when the type changes
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_NewTypeAfterClear_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // Clear the list in the middle of the loop
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    // Append after clear - this should set the new type
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Should return String because the list was empty and append sets the type
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_NewTypeAfterClear_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // Clear the list in the middle of the loop
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    // Append after clear - this should set the new type
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Should return String because clear makes the list empty, then append sets the type
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_MultipleAppendsAfterClear)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // Clear the list
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    // First append after clear
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Second append after clear (same type)
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 3.14);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Should return Number because all appends after clear are the same type
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_TypeConflictAfterClear)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // Clear the list
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    // First append after clear
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Second append after clear (different type - creates conflict)
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Should return Unknown because of type conflict after clear
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_WithInsertAndReplace)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // Clear the list
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    // Insert after clear
+    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    LLVMConstantRegister insertIndex(Compiler::StaticType::Number, 0);
+    LLVMConstantRegister insertValue(Compiler::StaticType::Bool, true);
+    insertList->workList = &list;
+    insertList->args.push_back({ Compiler::StaticType::Number, &insertIndex });
+    insertList->args.push_back({ Compiler::StaticType::Unknown, &insertValue });
+    instructionList.addInstruction(insertList);
+
+    // Replace after insert
+    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    LLVMConstantRegister replaceIndex(Compiler::StaticType::Number, 0);
+    LLVMConstantRegister replaceValue(Compiler::StaticType::Bool, false);
+    replaceList->workList = &list;
+    replaceList->args.push_back({ Compiler::StaticType::Number, &replaceIndex });
+    replaceList->args.push_back({ Compiler::StaticType::Unknown, &replaceValue });
+    instructionList.addInstruction(replaceList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Should return Bool because all operations after clear use Bool type
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Bool);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_ConditionalClear)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // If statement
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // Clear the list conditionally
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    // Append after clear
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "cleared");
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Else branch
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    // Append without clearing
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 42);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Should return Unknown due to type conflict between branches
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_AppendAfterClearingInIfBranch_DifferentType)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // If statement
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // Clear the list
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    // End if statement
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    // Append
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Should return Unknown because the clearing branch might or might not run
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_AppendAfterClearingInIfBranch_SameType)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // If statement
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // Clear the list
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    // End if statement
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    // Append
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 42);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Should return Number because there are no type conflicts
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_AppendAfterClearingInElseBranch_DifferentType)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // If statement
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // Else branch
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    // Clear the list
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    // End if statement
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    // Append
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Should return Unknown because the clearing branch might or might not run
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_AppendAfterClearingInElseBranch_SameType)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // If statement
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // Else branch
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    // Clear the list
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    // End if statement
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    // Append
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 42);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Should return Number because there are no type conflicts
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_MultipleClearsAndWrites)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // First clear
+    auto clearList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList1->workList = &list;
+    instructionList.addInstruction(clearList1);
+
+    // Append after first clear
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "first");
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Second clear
+    auto clearList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList2->workList = &list;
+    instructionList.addInstruction(clearList2);
+
+    // Append after second clear (different type)
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 42);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Should return Number because the last clear+append sequence determines the final type
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_ClearWithoutSubsequentWrite)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // Clear the list but don't write anything after
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Should return previous type since no writes occurred after clear
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Bool, false), Compiler::StaticType::Bool);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_ClearInNestedIf)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // Nested if statement
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // Clear and write in nested if
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Bool, true);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Should return Unknown because the type-changing branch might or might not run
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_AppendToEmptyListAndClearInIfBranch_SameType)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // Append in if branch
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Clear the list in if branch
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    // Append after if statement - should change type
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Should return String because the list remains empty after the if statement
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_AppendToEmptyListAndClearInIfBranch_DifferentType)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // Append in if branch
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Bool, true);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Clear the list in if branch
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    // Append after if statement - should change type
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Should return String because the list remains empty after the if statement
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_AppendToEmptyListAndClearInElseBranch_SameType)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    // Append in else branch
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Clear the list in else branch
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    // Append after if statement - should change type
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Should return String because the list remains empty after the if statement
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_AppendToEmptyListAndClearInElseBranch_DifferentType)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    // Append in else branch
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Bool, true);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Clear the list in else branch
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    // Append after if statement - should change type
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Should return String because the list remains empty after the if statement
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String);
+}

From ac4920e3a2dba999c5fffbedb60b699be5e79789 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Wed, 30 Jul 2025 18:58:33 +0200
Subject: [PATCH 41/79] LLVMTypeAnalyzer: Fix else branch handling in
 branchStart()

---
 src/engine/internal/llvm/llvmtypeanalyzer.cpp | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
index b80fa7f6..8b6f1406 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
@@ -269,18 +269,14 @@ LLVMInstruction *LLVMTypeAnalyzer::branchStart(LLVMInstruction *end) const
     LLVMInstruction *ins = end->previous;
     int level = 0;
 
-    while (ins && !((isLoopStart(ins) || isIfStart(ins)) && level == 0)) {
+    while (ins && !((isLoopStart(ins) || isIfStart(ins) || isElse(ins)) && level == 0)) {
         if (isLoopStart(ins) || isIfStart(ins)) {
             assert(level > 0);
             level--;
         }
 
-        if (isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) {
-            if (isElse(ins) && level == 0)
-                break;
-
+        if (isLoopEnd(ins) || isIfEnd(ins))
             level++;
-        }
 
         ins = ins->previous;
     };

From 9fc99eb84aa98dc0e9530f3ae7438e18430461cc Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Thu, 31 Jul 2025 13:05:53 +0200
Subject: [PATCH 42/79] LLVMTypeAnalyzer: Implement listType() for basic cases

---
 src/engine/internal/llvm/llvmtypeanalyzer.cpp |  140 +-
 src/engine/internal/llvm/llvmtypeanalyzer.h   |    5 +-
 test/llvm/CMakeLists.txt                      |    1 +
 test/llvm/type_analyzer/listtype_test.cpp     | 3119 +++++++++++++++++
 4 files changed, 3249 insertions(+), 16 deletions(-)
 create mode 100644 test/llvm/type_analyzer/listtype_test.cpp

diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
index 8b6f1406..63b1b0c4 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
@@ -22,13 +22,105 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(Variable *var, LL
     return variableTypeAfterBranch(var, start, previousType, visitedInstructions);
 }
 
+Compiler::StaticType LLVMTypeAnalyzer::listType(List *list, LLVMInstruction *pos, Compiler::StaticType previousType, bool isEmpty) const
+{
+    if (!list || !pos)
+        return Compiler::StaticType::Unknown;
+
+    InstructionSet visitedInstructions; // TODO: Handle cross-variable/list dependencies
+
+    LLVMInstruction *ins = pos;
+    LLVMInstruction *previous = nullptr;
+    std::pair<LLVMInstruction *, int> firstBranch = { nullptr, 0 };
+    std::pair<LLVMInstruction *, int> lastClear = { nullptr, 0 };
+    int level = 0;
+
+    // Find a start instruction (list clear in the top level or the first instruction)
+    while (ins) {
+        if (isLoopEnd(ins) || isIfEnd(ins))
+            level++;
+        else if (isLoopStart(ins) || isIfStart(ins) || isElse(ins)) {
+            if (!isElse(ins))
+                level--;
+
+            if (!firstBranch.first || level < firstBranch.second)
+                firstBranch = { ins, level };
+        } else if (isListClear(ins, list)) {
+            if (!lastClear.first || level < lastClear.second)
+                lastClear = { ins, level };
+        }
+
+        previous = ins;
+        ins = ins->previous;
+    }
+
+    if (firstBranch.first) {
+        assert(firstBranch.second == level);
+
+        // The first branch must be above the query point level
+        if (firstBranch.second == 0)
+            firstBranch.first = nullptr;
+    }
+
+    // Clear must be in the top level
+    if (lastClear.second != level)
+        lastClear.first = nullptr;
+
+    if (lastClear.first) {
+        ins = lastClear.first;
+        isEmpty = true;
+    } else
+        ins = previous;
+
+    // Process from the start instruction
+    while (ins && ins != pos) {
+        if (isLoopStart(ins) || isIfStart(ins)) {
+            do {
+                bool write;
+                Compiler::StaticType type = listTypeAfterBranch(list, ins, previousType, isEmpty, pos, write);
+
+                // If this branch contains the query point, return the final type
+                if (ins == firstBranch.first) {
+                    if (isEmpty || typesMatch(type, previousType))
+                        return type;
+                    else
+                        return Compiler::StaticType::Unknown;
+                }
+
+                // If there was a write, the list is no longer empty
+                if (write) {
+                    isEmpty = false;
+
+                    // The write could change the type
+                    if (!typesMatch(type, previousType))
+                        previousType = type;
+                }
+
+                // Skip the branch
+                ins = branchEnd(ins);
+            } while (isElse(ins)); // handle else branch
+        } else if (isListWrite(ins, list)) {
+            // List write instruction
+            Compiler::StaticType writeType = writeValueType(ins, visitedInstructions);
+
+            if (!handleListWrite(writeType, previousType, isEmpty))
+                return Compiler::StaticType::Unknown;
+        }
+
+        ins = ins->next;
+    }
+
+    assert(ins);
+    return previousType;
+}
+
 Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch(List *list, LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty) const
 {
     if (!list || !start)
         return previousType;
 
     bool write = false; // only used internally (the compiler doesn't need this)
-    return listTypeAfterBranch(list, start, previousType, isEmpty, write);
+    return listTypeAfterBranch(list, start, previousType, isEmpty, nullptr, write);
 }
 
 Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const
@@ -181,19 +273,23 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable *
     return previousType;
 }
 
-Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch(List *list, LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty, bool &write) const
+Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch(List *list, LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty, LLVMInstruction *query, bool &write) const
 {
     assert(isLoopStart(start) || isIfStart(start) || isElse(start));
 
     InstructionSet visitedInstructions; // TODO: Handle cross-variable/list dependencies
 
+    // Query point is only relevant in if statemenets because writes after them don't affect the result
+    if (isLoopStart(start))
+        query = nullptr;
+
     LLVMInstruction *ins = start->next;
     write = false;
 
     while (ins && !(isLoopEnd(ins) || isIfEnd(ins) || isElse(ins))) {
         if (isLoopStart(ins) || isIfStart(ins)) {
             do {
-                Compiler::StaticType type = listTypeAfterBranch(list, ins, previousType, isEmpty, write);
+                Compiler::StaticType type = listTypeAfterBranch(list, ins, previousType, isEmpty, query, write);
 
                 // If there was a write, the list is no longer empty
                 if (write) {
@@ -212,22 +308,14 @@ Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch(List *list, LLVMInstr
             Compiler::StaticType writeType = writeValueType(ins, visitedInstructions);
             write = true;
 
-            if (isEmpty) {
-                // In empty lists, writes of the same type determine the final type
-                // This is the first write found, it might determine the final type
-                previousType = writeType;
-
-                // The list is no longer empty
-                isEmpty = false;
-            } else if (!typesMatch(writeType, previousType)) {
-                // For non-empty lists, we can just check the write type
+            if (!handleListWrite(writeType, previousType, isEmpty))
                 return Compiler::StaticType::Unknown;
-            }
-        } else if (ins->type == LLVMInstruction::Type::ClearList && ins->workList == list) {
+        } else if (isListClear(ins, list)) {
             // The list is now empty
             isEmpty = true;
             write = false; // the write variable is only used to check if the list is still empty
-        }
+        } else if (ins == query)
+            break;
 
         ins = ins->next;
     }
@@ -236,6 +324,23 @@ Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch(List *list, LLVMInstr
     return previousType;
 }
 
+bool LLVMTypeAnalyzer::handleListWrite(Compiler::StaticType writeType, Compiler::StaticType &previousType, bool &isEmpty) const
+{
+    if (isEmpty) {
+        // In empty lists, writes of the same type determine the final type
+        // This is the first write found, it might determine the final type
+        previousType = writeType;
+
+        // The list is no longer empty
+        isEmpty = false;
+    } else if (!typesMatch(writeType, previousType)) {
+        // For non-empty lists, we can just check the write type
+        return false;
+    }
+
+    return true;
+}
+
 LLVMInstruction *LLVMTypeAnalyzer::branchEnd(LLVMInstruction *start) const
 {
     assert(start);
@@ -325,6 +430,11 @@ bool LLVMTypeAnalyzer::isListWrite(LLVMInstruction *ins, List *list) const
     return (LIST_WRITE_INSTRUCTIONS.find(ins->type) != LIST_WRITE_INSTRUCTIONS.cend() && ins->workList == list);
 }
 
+bool LLVMTypeAnalyzer::isListClear(LLVMInstruction *ins, List *list) const
+{
+    return (ins->type == LLVMInstruction::Type::ClearList && ins->workList == list);
+}
+
 Compiler::StaticType LLVMTypeAnalyzer::optimizeRegisterType(LLVMRegister *reg) const
 {
     // TODO: Move this method out if it's used in LLVMCodeBuilder too
diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.h b/src/engine/internal/llvm/llvmtypeanalyzer.h
index 187470a3..35b49732 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.h
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.h
@@ -14,6 +14,7 @@ class LLVMTypeAnalyzer
         Compiler::StaticType variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType) const;
         Compiler::StaticType variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType) const;
 
+        Compiler::StaticType listType(List *list, LLVMInstruction *pos, Compiler::StaticType previousType, bool isEmpty) const;
         Compiler::StaticType listTypeAfterBranch(List *list, LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty) const;
 
     private:
@@ -23,7 +24,8 @@ class LLVMTypeAnalyzer
         Compiler::StaticType variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const;
         Compiler::StaticType variableTypeAfterBranchFromEnd(Variable *var, LLVMInstruction *end, Compiler::StaticType previousType, bool &write, InstructionSet &visitedInstructions) const;
 
-        Compiler::StaticType listTypeAfterBranch(List *list, LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty, bool &write) const;
+        Compiler::StaticType listTypeAfterBranch(List *list, LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty, LLVMInstruction *query, bool &write) const;
+        bool handleListWrite(Compiler::StaticType writeType, Compiler::StaticType &previousType, bool &isEmpty) const;
 
         LLVMInstruction *branchEnd(LLVMInstruction *start) const;
         LLVMInstruction *branchStart(LLVMInstruction *end) const;
@@ -38,6 +40,7 @@ class LLVMTypeAnalyzer
         bool isVariableWrite(LLVMInstruction *ins, Variable *var) const;
 
         bool isListWrite(LLVMInstruction *ins, List *list) const;
+        bool isListClear(LLVMInstruction *ins, List *list) const;
 
         Compiler::StaticType optimizeRegisterType(LLVMRegister *reg) const;
         bool isWriteNoOp(LLVMInstruction *ins) const;
diff --git a/test/llvm/CMakeLists.txt b/test/llvm/CMakeLists.txt
index e1d005cc..95330a1d 100644
--- a/test/llvm/CMakeLists.txt
+++ b/test/llvm/CMakeLists.txt
@@ -23,6 +23,7 @@ add_executable(
   type_analyzer/variabletypeafterbranch_test.cpp
   type_analyzer/variabletype_test.cpp
   type_analyzer/listtypeafterbranch_test.cpp
+  type_analyzer/listtype_test.cpp
 )
 
 target_link_libraries(
diff --git a/test/llvm/type_analyzer/listtype_test.cpp b/test/llvm/type_analyzer/listtype_test.cpp
new file mode 100644
index 00000000..11930747
--- /dev/null
+++ b/test/llvm/type_analyzer/listtype_test.cpp
@@ -0,0 +1,3119 @@
+#include <scratchcpp/list.h>
+#include <engine/internal/llvm/llvmtypeanalyzer.h>
+#include <engine/internal/llvm/llvminstruction.h>
+#include <engine/internal/llvm/llvminstructionlist.h>
+#include <engine/internal/llvm/llvmconstantregister.h>
+#include <gtest/gtest.h>
+
+using namespace libscratchcpp;
+
+TEST(LLVMTypeAnalyzer_ListType, NullParams)
+{
+    LLVMTypeAnalyzer analyzer;
+    ASSERT_EQ(analyzer.listType(nullptr, nullptr, Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, NullList)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(nullptr, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, NullPos)
+{
+    LLVMTypeAnalyzer analyzer;
+    List list("", "");
+    ASSERT_EQ(analyzer.listType(&list, nullptr, Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, NoWriteOperationsKnownType_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, NoWriteOperationsKnownType_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, NoWriteOperationsUnknownType_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Unknown, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, NoWriteOperationsUnknownType_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Unknown, true), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteSameTypeNumber_Before_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 1.25);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteSameTypeNumber_Before_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 1.25);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteStringOptimization_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "1.25");
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // String "1.25" gets optimized to Number type
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteMultipleLists)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list1("", "");
+    List list2("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // Append to list1
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 6);
+    appendList1->workList = &list1;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Append to list2
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    appendList2->workList = &list2;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listType(&list1, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteFromUnknownType_Before_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMRegister value(Compiler::StaticType::Unknown);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteFromUnknownType_Before_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMRegister value(Compiler::StaticType::Unknown);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteToUnknownType_Before_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 5);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // The type is known because a number is appended before the point
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Unknown, true), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteToUnknownType_Before_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 5);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Unknown, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteDifferentTypeNumberToString_Before_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteDifferentTypeNumberToString_Before_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteDifferentTypeBoolToNumber_Before_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 1);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Bool, true), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteDifferentType_BeforeAndAfter)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "test");
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Bool, true);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, IfStatement_SingleWriteDifferentType_Before)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, IfStatement_SingleWriteDifferentType_After_IfBranch)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Since this isn't a loop, the write after the point doesn't affect the type
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, IfStatement_SingleWriteDifferentType_After_ElseBranch)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Since this isn't a loop, the write after the point doesn't affect the type
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, WriteSameTypeInLoop_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 1.25);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, WriteSameTypeInLoop_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 1.25);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, WriteDifferentTypeInLoop_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Type is not known because the loop might not run at all
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, WriteDifferentTypeInLoop_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Type is String because empty list can establish new type
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, ChangeTypeBeforeLoop_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 1.25);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, OverrideUnknownTypeBeforeLoop_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 1.25);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Unknown, true), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, WriteSameTypeInIfStatement_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 1.25);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, WriteDifferentTypeInIfStatement_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 5.8);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Type is not known because the if statement might not run at all
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, OverrideDifferentTypeBeforeIfElseStatement_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 1.25);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value3(Compiler::StaticType::Number, 2.5);
+    appendList3->workList = &list;
+    appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    instructionList.addInstruction(appendList3);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, true), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, OverrideUnknownTypeBeforeIfElseStatement_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 1.25);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value3(Compiler::StaticType::Number, 2.5);
+    appendList3->workList = &list;
+    appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    instructionList.addInstruction(appendList3);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Unknown, true), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, MultipleWritesSameTypeNumber_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // First write: string "abc" (incompatible with Number)
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "abc");
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Second write: number 5.25 (incompatible with previous String)
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 5.25);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should return Unknown type because of type conflict
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, MultipleWritesSameTypeString_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // First write: number 42 (establishes Number type for empty list)
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Second write: string "hello" (incompatible with Number)
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "hello");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should return Unknown type because of type conflict
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, true), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, MultipleWritesSameTypeUnknown_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // First write: unknown type
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMRegister value1(Compiler::StaticType::Unknown);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Second write: string "hello"
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "hello");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should return Unknown type because first write is unknown
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, true), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, MultipleWritesWithStringOptimization_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // First write: number 5
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Second write: string "3.14" (optimized to Number)
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "3.14");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should return Number type because the string gets optimized to number
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, MultipleWritesNumberToString_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // First write: number 42 (compatible with Number)
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Second write: string "hello" (incompatible with Number)
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "hello");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should return Unknown type because of type conflict
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, MultipleWritesNumberToString_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // First write: number 42 (establishes Number type for empty list)
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Second write: string "hello" (incompatible with Number)
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "hello");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should return Unknown type because of type conflict
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, MultipleWritesBoolToNumber_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 42.5);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should return Unknown type because Number conflicts with Bool
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Bool, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, MultipleWritesBoolToNumber_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 42.5);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should return Number type because empty list establishes new type
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Bool, true), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, MultipleWritesBoolToString_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "hello");
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should return Unknown type because String conflicts with Bool
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Bool, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, MultipleWritesBoolToString_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "hello");
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should return String type because empty list establishes new type
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Bool, true), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, MultipleWritesBoolToStringNumberOptimization_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "3.14");
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // String "3.14" gets optimized to Number, which conflicts with Bool
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Bool, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, MultipleWritesBoolToStringNumberOptimization_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "3.14");
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // String "3.14" gets optimized to Number type
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Bool, true), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, TypeChangeInIfBranch_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // First write - changes type
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "test");
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    // Second write - does not change type
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 42);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Returns unknown type because both branches might run
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, TypeChangeInIfBranch_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // First write - changes type
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "test");
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    // Second write - different type
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 42);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Returns unknown type because different types in branches
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, TypeChangeInElseBranch_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // First write - does not change type
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    // Second write - changes type
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Returns unknown type because both branches might run
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, TypeChangeInElseBranch_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // First write - establishes Number type
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    // Second write - establishes String type
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Returns unknown type because different types in branches
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, IfElseWithEqualTypes_SameType_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // First write - does not change type
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    // Second write - does not change type
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, IfElseWithEqualTypes_SameType_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // First write - establishes Number type
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    // Second write - establishes same Number type
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, IfElseWithEqualTypes_DifferentTypes_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // First write - changes type to string
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "Lorem");
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    // Second write - changes type to string
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "ipsum");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, IfElseWithEqualTypes_DifferentTypes_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // First write - establishes String type
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "Lorem");
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    // Second write - establishes same String type
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "ipsum");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, NestedLoopWithTypeChange_Before_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(outerLoop);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // List write inside outer loop
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Inner loop begin
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(innerLoop);
+
+    // List write inside inner loop
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    // Inner loop end
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(innerEnd);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(outerEnd);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, NestedLoopWithTypeChange_Before_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(outerLoop);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // List write inside outer loop
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Inner loop begin
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(innerLoop);
+
+    // List write inside inner loop
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    // Inner loop end
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(innerEnd);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(outerEnd);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, NestedLoopWithTypeChange_BeforeInner_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(outerLoop);
+
+    // List write inside outer loop
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Inner loop begin
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(innerLoop);
+
+    // List write inside inner loop
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    // Inner loop end
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(innerEnd);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(outerEnd);
+
+    // Returns Unknown because a string might be added
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, NestedLoopWithTypeChange_BeforeInner_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(outerLoop);
+
+    // List write inside outer loop
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Inner loop begin
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(innerLoop);
+
+    // List write inside inner loop
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    // Inner loop end
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(innerEnd);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(outerEnd);
+
+    // Returns Unknown because a string might be added
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, NestedLoopWithTypeChange_AfterWriteInsideInner_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(outerLoop);
+
+    // List write inside outer loop
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Inner loop begin
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(innerLoop);
+
+    // List write inside inner loop
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Inner loop end
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(innerEnd);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(outerEnd);
+
+    // Returns Unknown because a string might be added
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, NestedLoopWithTypeChange_AfterWriteInsideInner_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(outerLoop);
+
+    // List write inside outer loop
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Inner loop begin
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(innerLoop);
+
+    // List write inside inner loop
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Inner loop end
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(innerEnd);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(outerEnd);
+
+    // Returns Unknown because a string might be added
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, NestedLoopWithTypeChange_After_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(outerLoop);
+
+    // List write inside outer loop
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Inner loop begin
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(innerLoop);
+
+    // List write inside inner loop
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    // Inner loop end
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(innerEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(outerEnd);
+
+    // Type is not known because the inner loop might not run at all
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, NestedLoopWithTypeChange_After_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(outerLoop);
+
+    // List write inside outer loop
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Inner loop begin
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(innerLoop);
+
+    // List write inside inner loop
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    // Inner loop end
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(innerEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(outerEnd);
+
+    // Type is not known because the inner loop might not run at all
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, NestedLoopWithoutTypeChange_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginWhileLoop, nullptr, false);
+    instructionList.addInstruction(outerLoop);
+
+    // List write inside outer loop
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Inner loop begin
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(innerLoop);
+
+    // List write inside inner loop
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 2.5);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    // Inner loop end
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(innerEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(outerEnd);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, NestedLoopWithoutTypeChange_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginWhileLoop, nullptr, false);
+    instructionList.addInstruction(outerLoop);
+
+    // List write inside outer loop
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Inner loop begin
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(innerLoop);
+
+    // List write inside inner loop
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 2.5);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    // Inner loop end
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(innerEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(outerEnd);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, NestedLoopTypeChangesMultipleTimes_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(outerLoop);
+
+    // List write inside outer loop
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Inner loop begin
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false);
+    instructionList.addInstruction(innerLoop);
+
+    // List write inside inner loop
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    // Inner loop end
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(innerEnd);
+
+    // List write after inner loop
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value3(Compiler::StaticType::Number, 2);
+    appendList3->workList = &list;
+    appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    instructionList.addInstruction(appendList3);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(outerEnd);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, NestedLoopTypeChangesMultipleTimes_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(outerLoop);
+
+    // List write inside outer loop
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Inner loop begin
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false);
+    instructionList.addInstruction(innerLoop);
+
+    // List write inside inner loop
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    // Inner loop end
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(innerEnd);
+
+    // List write after inner loop
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value3(Compiler::StaticType::Number, 2);
+    appendList3->workList = &list;
+    appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    instructionList.addInstruction(appendList3);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(outerEnd);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, MultipleNestedLoopsWithTypeChange_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(outerLoop);
+
+    // List write inside outer loop
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Inner loop 1 begin
+    auto innerLoop1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(innerLoop1);
+
+    // List write inside inner loop 1
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    // Inner loop 2 begin
+    auto innerLoop2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(innerLoop2);
+
+    // List write inside inner loop 2
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value3(Compiler::StaticType::String, "abc");
+    appendList3->workList = &list;
+    appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    instructionList.addInstruction(appendList3);
+
+    // Inner loop 2 end
+    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(innerEnd2);
+
+    // Inner loop 1 end
+    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(innerEnd1);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(outerEnd);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, MultipleNestedLoopsWithTypeChange_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(outerLoop);
+
+    // List write inside outer loop
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Inner loop 1 begin
+    auto innerLoop1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(innerLoop1);
+
+    // List write inside inner loop 1
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    // Inner loop 2 begin
+    auto innerLoop2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(innerLoop2);
+
+    // List write inside inner loop 2
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value3(Compiler::StaticType::String, "abc");
+    appendList3->workList = &list;
+    appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    instructionList.addInstruction(appendList3);
+
+    // Inner loop 2 end
+    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(innerEnd2);
+
+    // Inner loop 1 end
+    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(innerEnd1);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(outerEnd);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, MultipleNestedLoopsWithMultipleTypeChanges_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(outerLoop);
+
+    // List write inside outer loop
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Inner loop 1 begin
+    auto innerLoop1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(innerLoop1);
+
+    // Inner loop 2 begin
+    auto innerLoop2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(innerLoop2);
+
+    // List write inside inner loop 2
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "abc");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    // Inner loop 2 end
+    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(innerEnd2);
+
+    // List write inside inner loop 1
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value3(Compiler::StaticType::Number, 2.75);
+    appendList3->workList = &list;
+    appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    instructionList.addInstruction(appendList3);
+
+    // Inner loop 1 end
+    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(innerEnd1);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(outerEnd);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, MultipleNestedLoopsWithMultipleTypeChanges_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(outerLoop);
+
+    // List write inside outer loop
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Inner loop 1 begin
+    auto innerLoop1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(innerLoop1);
+
+    // Inner loop 2 begin
+    auto innerLoop2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(innerLoop2);
+
+    // List write inside inner loop 2
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "abc");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    // Inner loop 2 end
+    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(innerEnd2);
+
+    // List write inside inner loop 1
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value3(Compiler::StaticType::Number, 2.75);
+    appendList3->workList = &list;
+    appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    instructionList.addInstruction(appendList3);
+
+    // Inner loop 1 end
+    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(innerEnd1);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(outerEnd);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, SameTypeIfElseInLoopWithTypeChange_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // Outer loop begin
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(outerLoop);
+
+    // Inner if statement begin
+    auto innerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(innerIf);
+
+    // List write inside inner if statement if branch
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "abc");
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Inner if statement else branch
+    auto innerElse = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(innerElse);
+
+    // List write inside inner if statement else branch
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "def");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    // Inner if statement end
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(innerEnd);
+
+    // Outer loop end
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(outerEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // A type conflict always occurs
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, InsertToList_SameType_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    LLVMConstantRegister index(Compiler::StaticType::Number, 1);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 42.5);
+    insertList->workList = &list;
+    insertList->args.push_back({ Compiler::StaticType::Number, &index });
+    insertList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(insertList);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, InsertToList_DifferentType_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    LLVMConstantRegister index(Compiler::StaticType::Number, 0);
+    LLVMConstantRegister value(Compiler::StaticType::String, "hello");
+    insertList->workList = &list;
+    insertList->args.push_back({ Compiler::StaticType::Number, &index });
+    insertList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(insertList);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, InsertToList_InLoop_TypeConflict)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto insertList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    LLVMConstantRegister index1(Compiler::StaticType::Number, 0);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 123);
+    insertList1->workList = &list;
+    insertList1->args.push_back({ Compiler::StaticType::Number, &index1 });
+    insertList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(insertList1);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    auto insertList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    LLVMConstantRegister index2(Compiler::StaticType::Number, 1);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    insertList2->workList = &list;
+    insertList2->args.push_back({ Compiler::StaticType::Number, &index2 });
+    insertList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(insertList2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, ListReplace_SameType_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    LLVMConstantRegister index(Compiler::StaticType::Number, 0);
+    LLVMConstantRegister value(Compiler::StaticType::String, "replaced");
+    replaceList->workList = &list;
+    replaceList->args.push_back({ Compiler::StaticType::Number, &index });
+    replaceList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(replaceList);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, ListReplace_DifferentType_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    LLVMConstantRegister index(Compiler::StaticType::Number, 0);
+    LLVMConstantRegister value(Compiler::StaticType::Bool, true);
+    replaceList->workList = &list;
+    replaceList->args.push_back({ Compiler::StaticType::Number, &index });
+    replaceList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(replaceList);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, ListReplace_WithStringOptimization)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    LLVMConstantRegister index(Compiler::StaticType::Number, 0);
+    LLVMConstantRegister value(Compiler::StaticType::String, "42.75");
+    replaceList->workList = &list;
+    replaceList->args.push_back({ Compiler::StaticType::Number, &index });
+    replaceList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(replaceList);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // String "42.75" gets optimized to Number type
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, MixedWriteOperations_TypeConflict)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // Append a number
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList);
+
+    // Insert a string
+    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    LLVMConstantRegister index(Compiler::StaticType::Number, 0);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "hello");
+    insertList->workList = &list;
+    insertList->args.push_back({ Compiler::StaticType::Number, &index });
+    insertList->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(insertList);
+
+    // Replace with a boolean
+    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    LLVMConstantRegister index2(Compiler::StaticType::Number, 1);
+    LLVMConstantRegister value3(Compiler::StaticType::Bool, true);
+    replaceList->workList = &list;
+    replaceList->args.push_back({ Compiler::StaticType::Number, &index2 });
+    replaceList->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    instructionList.addInstruction(replaceList);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should be Unknown due to multiple type conflicts
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, MixedWriteOperations_SameType)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // Append a string
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "hello");
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList);
+
+    // Insert another string
+    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    LLVMConstantRegister index(Compiler::StaticType::Number, 0);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "world");
+    insertList->workList = &list;
+    insertList->args.push_back({ Compiler::StaticType::Number, &index });
+    insertList->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(insertList);
+
+    // Replace with another string
+    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    LLVMConstantRegister index2(Compiler::StaticType::Number, 1);
+    LLVMConstantRegister value3(Compiler::StaticType::String, "test");
+    replaceList->workList = &list;
+    replaceList->args.push_back({ Compiler::StaticType::Number, &index2 });
+    replaceList->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    instructionList.addInstruction(replaceList);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should be String type since all operations use strings
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, ComplexMixedOperations)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // Append a number
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 123);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList);
+
+    // Insert another number
+    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    LLVMConstantRegister index1(Compiler::StaticType::Number, 0);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 456);
+    insertList->workList = &list;
+    insertList->args.push_back({ Compiler::StaticType::Number, &index1 });
+    insertList->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(insertList);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Replace with a string (creates type conflict)
+    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    LLVMConstantRegister index2(Compiler::StaticType::Number, 0);
+    LLVMConstantRegister value3(Compiler::StaticType::String, "conflict");
+    replaceList->workList = &list;
+    replaceList->args.push_back({ Compiler::StaticType::Number, &index2 });
+    replaceList->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    instructionList.addInstruction(replaceList);
+
+    // Should be Number type at the function call point, before the conflicting replace
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, true), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, ComplexMixedOperations_InLoop)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // Append a number
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 123);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList);
+
+    // Insert another number
+    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    LLVMConstantRegister index1(Compiler::StaticType::Number, 0);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 456);
+    insertList->workList = &list;
+    insertList->args.push_back({ Compiler::StaticType::Number, &index1 });
+    insertList->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(insertList);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Replace with a string (creates type conflict)
+    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    LLVMConstantRegister index2(Compiler::StaticType::Number, 0);
+    LLVMConstantRegister value3(Compiler::StaticType::String, "conflict");
+    replaceList->workList = &list;
+    replaceList->args.push_back({ Compiler::StaticType::Number, &index2 });
+    replaceList->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    instructionList.addInstruction(replaceList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, true), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, ClearAndRebuild_WithDifferentTypes)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // Initial append
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "initial");
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Clear the list
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    // Rebuild with different operations and types
+    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    LLVMConstantRegister index(Compiler::StaticType::Number, 0);
+    LLVMConstantRegister value2(Compiler::StaticType::Bool, true);
+    insertList->workList = &list;
+    insertList->args.push_back({ Compiler::StaticType::Number, &index });
+    insertList->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(insertList);
+
+    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    LLVMConstantRegister index2(Compiler::StaticType::Number, 0);
+    LLVMConstantRegister value3(Compiler::StaticType::Bool, false);
+    replaceList->workList = &list;
+    replaceList->args.push_back({ Compiler::StaticType::Number, &index2 });
+    replaceList->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    instructionList.addInstruction(replaceList);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should be Bool type since clear resets and all subsequent operations use booleans
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::Bool);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_NewTypeAfterClear_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // Clear the list in the middle of the loop
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    // Append after clear - this should set the new type
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should return String because the list was empty and append sets the type
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_NewTypeAfterClear_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // Clear the list in the middle of the loop
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    // Append after clear - this should set the new type
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should return String because clear makes the list empty, then append sets the type
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_MultipleAppendsAfterClear)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // Clear the list
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    // First append after clear
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Second append after clear (same type)
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 3.14);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should return Number because all appends after clear are the same type
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_TypeConflictAfterClear)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // Clear the list
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    // First append after clear
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Second append after clear (different type - creates conflict)
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should return Unknown because of type conflict after clear
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_WithInsertAndReplace)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // Clear the list
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    // Insert after clear
+    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    LLVMConstantRegister insertIndex(Compiler::StaticType::Number, 0);
+    LLVMConstantRegister insertValue(Compiler::StaticType::Bool, true);
+    insertList->workList = &list;
+    insertList->args.push_back({ Compiler::StaticType::Number, &insertIndex });
+    insertList->args.push_back({ Compiler::StaticType::Unknown, &insertValue });
+    instructionList.addInstruction(insertList);
+
+    // Replace after insert
+    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    LLVMConstantRegister replaceIndex(Compiler::StaticType::Number, 0);
+    LLVMConstantRegister replaceValue(Compiler::StaticType::Bool, false);
+    replaceList->workList = &list;
+    replaceList->args.push_back({ Compiler::StaticType::Number, &replaceIndex });
+    replaceList->args.push_back({ Compiler::StaticType::Unknown, &replaceValue });
+    instructionList.addInstruction(replaceList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should return Bool because all operations after clear use Bool type
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Bool);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_ConditionalClear)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // If statement
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // Clear the list conditionally
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    // Append after clear
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "cleared");
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Else branch
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    // Append without clearing
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 42);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should return Unknown due to type conflict between branches
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_AppendAfterClearingInIfBranch_DifferentType)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // If statement
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // Clear the list
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    // End if statement
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    // Append
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should return Unknown because the clearing branch might or might not run
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_AppendAfterClearingInIfBranch_SameType)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // If statement
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // Clear the list
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    // End if statement
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    // Append
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 42);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should return Number because there are no type conflicts
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_AppendAfterClearingInElseBranch_DifferentType)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // If statement
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // Else branch
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    // Clear the list
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    // End if statement
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    // Append
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::String, "test");
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should return Unknown because the clearing branch might or might not run
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_AppendAfterClearingInElseBranch_SameType)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // If statement
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // Else branch
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    // Clear the list
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    // End if statement
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    // Append
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 42);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should return Number because there are no type conflicts
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_MultipleClearsAndWrites)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // First clear
+    auto clearList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList1->workList = &list;
+    instructionList.addInstruction(clearList1);
+
+    // Append after first clear
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "first");
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Second clear
+    auto clearList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList2->workList = &list;
+    instructionList.addInstruction(clearList2);
+
+    // Append after second clear (different type)
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 42);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should return Number because the last clear+append sequence determines the final type
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_ClearWithoutSubsequentWrite)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // Clear the list but don't write anything after
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should return previous type since no writes occurred after clear
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Bool, false), Compiler::StaticType::Bool);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_ClearInNestedIf)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // Nested if statement
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // Clear and write in nested if
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Bool, true);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should return Unknown because the type-changing branch might or might not run
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_AppendToEmptyListAndClearInIfBranch_SameType)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // Append in if branch
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Clear the list in if branch
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    // Append after if statement - should change type
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should return String because the list remains empty after the if statement
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_AppendToEmptyListAndClearInIfBranch_DifferentType)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // Append in if branch
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Bool, true);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Clear the list in if branch
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    // Append after if statement - should change type
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should return String because the list remains empty after the if statement
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_AppendToEmptyListAndClearInElseBranch_SameType)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    // Append in else branch
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Clear the list in else branch
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    // Append after if statement - should change type
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should return String because the list remains empty after the if statement
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_AppendToEmptyListAndClearInElseBranch_DifferentType)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    // Append in else branch
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Bool, true);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Clear the list in else branch
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    // Append after if statement - should change type
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should return String because the list remains empty after the if statement
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String);
+}

From 528d3cb5260d601d0414829c17c57131e849444e Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Thu, 31 Jul 2025 13:42:53 +0200
Subject: [PATCH 43/79] LLVMTypeAnalyzer: Fix sequential if statements/loops

---
 src/engine/internal/llvm/llvmtypeanalyzer.cpp |  20 +-
 test/llvm/type_analyzer/listtype_test.cpp     | 254 ++++++++++++++++++
 test/llvm/type_analyzer/variabletype_test.cpp | 127 +++++++++
 3 files changed, 393 insertions(+), 8 deletions(-)

diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
index 63b1b0c4..3d5273fc 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
@@ -148,8 +148,8 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstructi
     // Check the last write operation before the instruction
     LLVMInstruction *ins = pos;
     LLVMInstruction *write = nullptr;
-    LLVMInstruction *firstBranch = nullptr;
-    LLVMInstruction *firstElseBranch = nullptr;
+    std::pair<LLVMInstruction *, int> firstBranch = { nullptr, 0 };
+    std::pair<LLVMInstruction *, int> firstElseBranch = { nullptr, 0 };
     LLVMInstruction *ourBranch = nullptr;
     int level = 0;
 
@@ -160,11 +160,15 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstructi
             if (!ourBranch && level == 0)
                 ourBranch = ins;
 
+            if (!firstBranch.first || level < firstBranch.second)
+                firstBranch = { ins, level };
+
             level--;
-            firstBranch = ins;
         } else if (isElse(ins)) {
             // Skip if branch if coming from else
-            firstElseBranch = ins;
+            if (!firstElseBranch.first || level < firstElseBranch.second)
+                firstElseBranch = { ins, level };
+
             ins = branchStart(ins);
             continue;
         } else if (isVariableWrite(ins, var) && !isWriteNoOp(ins)) {
@@ -177,9 +181,9 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstructi
         ins = ins->previous;
     }
 
-    if (firstBranch) {
+    if (firstBranch.first) {
         // Analyze the first branch and else branch
-        bool ignoreWriteAfterPos = (isIfStart(firstBranch) && firstBranch == ourBranch);
+        bool ignoreWriteAfterPos = (isIfStart(firstBranch.first) && firstBranch.first == ourBranch);
 
         if (write)
             previousType = writeValueType(write, visitedInstructions); // write operation overrides previous type
@@ -188,8 +192,8 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstructi
         Compiler::StaticType elseBranchType = previousType;
 
         if (!ignoreWriteAfterPos) {
-            firstBranchType = variableTypeAfterBranch(var, firstBranch, previousType, visitedInstructions);
-            elseBranchType = variableTypeAfterBranch(var, firstElseBranch, previousType, visitedInstructions);
+            firstBranchType = variableTypeAfterBranch(var, firstBranch.first, previousType, visitedInstructions);
+            elseBranchType = variableTypeAfterBranch(var, firstElseBranch.first, previousType, visitedInstructions);
         }
 
         if (typesMatch(firstBranchType, elseBranchType))
diff --git a/test/llvm/type_analyzer/listtype_test.cpp b/test/llvm/type_analyzer/listtype_test.cpp
index 11930747..baf94722 100644
--- a/test/llvm/type_analyzer/listtype_test.cpp
+++ b/test/llvm/type_analyzer/listtype_test.cpp
@@ -1306,6 +1306,260 @@ TEST(LLVMTypeAnalyzer_ListType, IfElseWithEqualTypes_DifferentTypes_Empty)
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String);
 }
 
+TEST(LLVMTypeAnalyzer_ListType, IfStatementAfterLoop_SameTypes_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(loopStart);
+
+    // First write - does not change type
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(loopEnd);
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // Second write - does not change type
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 2);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, IfStatementAfterLoop_SameTypes_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(loopStart);
+
+    // First write - establishes type for empty list
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(loopEnd);
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // Second write - same type
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 2);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, IfStatementAfterLoop_DifferentTypes_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(loopStart);
+
+    // First write - does not change type
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(loopEnd);
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // Second write - changes type
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, IfStatementAfterLoop_DifferentTypes_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(loopStart);
+
+    // First write - establishes Number type for empty list
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(loopEnd);
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // Second write - adds string
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, TwoIfStatements_DifferentTypes_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // First write - does not change type
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    // Second write - does not change type
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 4);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    // Third write - adds string (in else branch)
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value3(Compiler::StaticType::String, "test");
+    appendList3->workList = &list;
+    appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    instructionList.addInstruction(appendList3);
+
+    ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, TwoIfStatements_DifferentTypes_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // First write - establishes Number type
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    // Second write - same Number type
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 4);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    // Third write - adds String (in else branch)
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value3(Compiler::StaticType::String, "test");
+    appendList3->workList = &list;
+    appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    instructionList.addInstruction(appendList3);
+
+    ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown);
+}
+
 TEST(LLVMTypeAnalyzer_ListType, NestedLoopWithTypeChange_Before_NonEmpty)
 {
     LLVMTypeAnalyzer analyzer;
diff --git a/test/llvm/type_analyzer/variabletype_test.cpp b/test/llvm/type_analyzer/variabletype_test.cpp
index 63739f6a..1d167588 100644
--- a/test/llvm/type_analyzer/variabletype_test.cpp
+++ b/test/llvm/type_analyzer/variabletype_test.cpp
@@ -1296,6 +1296,133 @@ TEST(LLVMTypeAnalyzer_VariableType, IfElseWithEqualTypes_DifferentTypes)
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
 }
 
+TEST(LLVMTypeAnalyzer_VariableType, IfStatementAfterLoop_SameTypes)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var("", "");
+
+    auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(loopStart);
+
+    // First write - does not change type
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(loopEnd);
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(ifStart);
+
+    // Second write - does not change type
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 2);
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(ifEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, IfStatementAfterLoop_DifferentTypes)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var("", "");
+
+    auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    list.addInstruction(loopStart);
+
+    // First write - does not change type
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    list.addInstruction(loopEnd);
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(ifStart);
+
+    // Second write - changes type
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "test");
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(ifEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_VariableType, TwoIfStatements_DifferentTypes)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var("", "");
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(ifStart);
+
+    // First write - does not change type
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    setVar1->workVariable = &var;
+    setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    list.addInstruction(setVar1);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    list.addInstruction(elseStart);
+
+    // Second write - does not change type
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 4);
+    setVar2->workVariable = &var;
+    setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    list.addInstruction(setVar2);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(ifEnd);
+
+    ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    list.addInstruction(ifStart);
+
+    elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    list.addInstruction(elseStart);
+
+    // Third write - changes type (in else branch)
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value3(Compiler::StaticType::String, "test");
+    setVar3->workVariable = &var;
+    setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
+    list.addInstruction(setVar3);
+
+    ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    list.addInstruction(ifEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    list.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
+}
+
 TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithTypeChange_Before)
 {
     LLVMTypeAnalyzer analyzer;

From 5c77e1171271f1dc7785e04114acd2b92bf1730b Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Fri, 1 Aug 2025 13:33:53 +0200
Subject: [PATCH 44/79] LLVMTypeAnalyzer: Handle cross-list dependencies

---
 src/engine/internal/llvm/llvmtypeanalyzer.cpp | 287 ++++----
 src/engine/internal/llvm/llvmtypeanalyzer.h   |  34 +-
 test/llvm/type_analyzer/listtype_test.cpp     | 634 ++++++++++++++++++
 .../listtypeafterbranch_test.cpp              | 305 +++++++++
 4 files changed, 1139 insertions(+), 121 deletions(-)

diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
index 3d5273fc..b0d4a6c9 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
@@ -13,7 +13,8 @@ static const std::unordered_set<LLVMInstruction::Type> LIST_WRITE_INSTRUCTIONS =
 Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType) const
 {
     InstructionSet visitedInstructions;
-    return variableType(var, pos, previousType, visitedInstructions);
+    std::unordered_map<List *, Compiler::StaticType> listTypes;
+    return variableType(var, pos, previousType, listTypes, visitedInstructions);
 }
 
 Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType) const
@@ -24,106 +25,22 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(Variable *var, LL
 
 Compiler::StaticType LLVMTypeAnalyzer::listType(List *list, LLVMInstruction *pos, Compiler::StaticType previousType, bool isEmpty) const
 {
-    if (!list || !pos)
-        return Compiler::StaticType::Unknown;
-
-    InstructionSet visitedInstructions; // TODO: Handle cross-variable/list dependencies
-
-    LLVMInstruction *ins = pos;
-    LLVMInstruction *previous = nullptr;
-    std::pair<LLVMInstruction *, int> firstBranch = { nullptr, 0 };
-    std::pair<LLVMInstruction *, int> lastClear = { nullptr, 0 };
-    int level = 0;
-
-    // Find a start instruction (list clear in the top level or the first instruction)
-    while (ins) {
-        if (isLoopEnd(ins) || isIfEnd(ins))
-            level++;
-        else if (isLoopStart(ins) || isIfStart(ins) || isElse(ins)) {
-            if (!isElse(ins))
-                level--;
-
-            if (!firstBranch.first || level < firstBranch.second)
-                firstBranch = { ins, level };
-        } else if (isListClear(ins, list)) {
-            if (!lastClear.first || level < lastClear.second)
-                lastClear = { ins, level };
-        }
-
-        previous = ins;
-        ins = ins->previous;
-    }
-
-    if (firstBranch.first) {
-        assert(firstBranch.second == level);
-
-        // The first branch must be above the query point level
-        if (firstBranch.second == 0)
-            firstBranch.first = nullptr;
-    }
-
-    // Clear must be in the top level
-    if (lastClear.second != level)
-        lastClear.first = nullptr;
-
-    if (lastClear.first) {
-        ins = lastClear.first;
-        isEmpty = true;
-    } else
-        ins = previous;
-
-    // Process from the start instruction
-    while (ins && ins != pos) {
-        if (isLoopStart(ins) || isIfStart(ins)) {
-            do {
-                bool write;
-                Compiler::StaticType type = listTypeAfterBranch(list, ins, previousType, isEmpty, pos, write);
-
-                // If this branch contains the query point, return the final type
-                if (ins == firstBranch.first) {
-                    if (isEmpty || typesMatch(type, previousType))
-                        return type;
-                    else
-                        return Compiler::StaticType::Unknown;
-                }
-
-                // If there was a write, the list is no longer empty
-                if (write) {
-                    isEmpty = false;
-
-                    // The write could change the type
-                    if (!typesMatch(type, previousType))
-                        previousType = type;
-                }
-
-                // Skip the branch
-                ins = branchEnd(ins);
-            } while (isElse(ins)); // handle else branch
-        } else if (isListWrite(ins, list)) {
-            // List write instruction
-            Compiler::StaticType writeType = writeValueType(ins, visitedInstructions);
-
-            if (!handleListWrite(writeType, previousType, isEmpty))
-                return Compiler::StaticType::Unknown;
-        }
-
-        ins = ins->next;
-    }
-
-    assert(ins);
-    return previousType;
+    InstructionSet visitedInstructions;
+    std::unordered_map<List *, Compiler::StaticType> listTypes;
+    return listType(list, pos, previousType, isEmpty, listTypes, visitedInstructions);
 }
 
 Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch(List *list, LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty) const
 {
-    if (!list || !start)
-        return previousType;
-
     bool write = false; // only used internally (the compiler doesn't need this)
-    return listTypeAfterBranch(list, start, previousType, isEmpty, nullptr, write);
+    InstructionSet visitedInstructions;
+    std::unordered_map<List *, Compiler::StaticType> listTypes;
+    return listTypeAfterBranch(list, start, previousType, isEmpty, nullptr, write, listTypes, visitedInstructions);
 }
 
-Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const
+Compiler::StaticType
+LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType, std::unordered_map<List *, Compiler::StaticType> listTypes, InstructionSet &visitedInstructions)
+    const
 {
     if (!var || !pos)
         return Compiler::StaticType::Unknown;
@@ -186,7 +103,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstructi
         bool ignoreWriteAfterPos = (isIfStart(firstBranch.first) && firstBranch.first == ourBranch);
 
         if (write)
-            previousType = writeValueType(write, visitedInstructions); // write operation overrides previous type
+            previousType = writeValueType(write, listTypes, visitedInstructions); // write operation overrides previous type
 
         Compiler::StaticType firstBranchType = previousType;
         Compiler::StaticType elseBranchType = previousType;
@@ -202,7 +119,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstructi
             return Compiler::StaticType::Unknown;
     } else if (write) {
         // There wasn't any branch found, so we can just check the last write operation
-        return writeValueType(write, visitedInstructions);
+        return writeValueType(write, listTypes, visitedInstructions);
     }
 
     // No write operation found
@@ -221,10 +138,17 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(Variable *var, LL
 
     // Process the branch from end
     bool write = false; // only used internally (the compiler doesn't need this)
-    return variableTypeAfterBranchFromEnd(var, end, previousType, write, visitedInstructions);
+    std::unordered_map<List *, Compiler::StaticType> listTypes;
+    return variableTypeAfterBranchFromEnd(var, end, previousType, write, listTypes, visitedInstructions);
 }
 
-Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable *var, LLVMInstruction *end, Compiler::StaticType previousType, bool &write, InstructionSet &visitedInstructions) const
+Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(
+    Variable *var,
+    LLVMInstruction *end,
+    Compiler::StaticType previousType,
+    bool &write,
+    std::unordered_map<List *, Compiler::StaticType> listTypes,
+    InstructionSet &visitedInstructions) const
 {
     // Find the last write instruction
     LLVMInstruction *ins = end->previous;
@@ -233,7 +157,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable *
     while (ins && !isLoopStart(ins) && !isIfStart(ins)) {
         if (isLoopEnd(ins) || isIfEnd(ins) || isElse(ins)) {
             // Process the nested loop or if statement
-            Compiler::StaticType ret = variableTypeAfterBranchFromEnd(var, ins, previousType, write, visitedInstructions);
+            Compiler::StaticType ret = variableTypeAfterBranchFromEnd(var, ins, previousType, write, listTypes, visitedInstructions);
 
             if (typesMatch(ret, previousType)) {
                 if (write)
@@ -245,7 +169,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable *
 
             if (isElse(ins)) {
                 // Process if branch (the else branch is already processed)
-                ret = variableTypeAfterBranchFromEnd(var, ins, previousType, write, visitedInstructions);
+                ret = variableTypeAfterBranchFromEnd(var, ins, previousType, write, listTypes, visitedInstructions);
 
                 if (typesMatch(ret, previousType)) {
                     if (write) {
@@ -261,7 +185,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable *
             }
         } else if (isVariableWrite(ins, var) && !isWriteNoOp(ins)) {
             // Variable write instruction
-            Compiler::StaticType writeType = writeValueType(ins, visitedInstructions);
+            Compiler::StaticType writeType = writeValueType(ins, listTypes, visitedInstructions);
             write = true;
 
             if (typesMatch(writeType, previousType))
@@ -277,23 +201,134 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(Variable *
     return previousType;
 }
 
-Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch(List *list, LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty, LLVMInstruction *query, bool &write) const
+Compiler::StaticType LLVMTypeAnalyzer::
+    listType(List *list, LLVMInstruction *pos, Compiler::StaticType previousType, bool isEmpty, std::unordered_map<List *, Compiler::StaticType> listTypes, InstructionSet &visitedInstructions) const
 {
-    assert(isLoopStart(start) || isIfStart(start) || isElse(start));
+    if (!list || !pos)
+        return Compiler::StaticType::Unknown;
+
+    /*
+     * If the given instruction has already been processed,
+     * it means there's a circular dependency with an unknown type.
+     * See variableType()
+     */
+    if (visitedInstructions.find(pos) != visitedInstructions.cend()) {
+        // Circular dependencies are rare (and bad) so don't optimize them
+        // TODO: The (previousType != Compiler::StaticType::Unknown) case isn't handled in tests
+        // Add a test case for it if you find it...
+        assert(previousType == Compiler::StaticType::Unknown);
+        return /*Compiler::StaticType::Unknown*/ previousType;
+    }
 
-    InstructionSet visitedInstructions; // TODO: Handle cross-variable/list dependencies
+    visitedInstructions.insert(pos);
+    listTypes[list] = previousType;
 
-    // Query point is only relevant in if statemenets because writes after them don't affect the result
-    if (isLoopStart(start))
-        query = nullptr;
+    LLVMInstruction *ins = pos;
+    LLVMInstruction *previous = nullptr;
+    std::pair<LLVMInstruction *, int> firstBranch = { nullptr, 0 };
+    std::pair<LLVMInstruction *, int> lastClear = { nullptr, 0 };
+    int level = 0;
 
-    LLVMInstruction *ins = start->next;
+    // Find a start instruction (list clear in the top level or the first instruction)
+    while (ins) {
+        if (isLoopEnd(ins) || isIfEnd(ins))
+            level++;
+        else if (isLoopStart(ins) || isIfStart(ins) || isElse(ins)) {
+            if (!isElse(ins))
+                level--;
+
+            if (!firstBranch.first || level < firstBranch.second)
+                firstBranch = { ins, level };
+        } else if (isListClear(ins, list)) {
+            if (!lastClear.first || level < lastClear.second)
+                lastClear = { ins, level };
+        }
+
+        previous = ins;
+        ins = ins->previous;
+    }
+
+    if (firstBranch.first) {
+        assert(firstBranch.second == level);
+
+        // The first branch must be above the query point level
+        if (firstBranch.second == 0)
+            firstBranch.first = nullptr;
+    }
+
+    // Clear must be in the top level
+    if (lastClear.second != level)
+        lastClear.first = nullptr;
+
+    if (lastClear.first) {
+        ins = lastClear.first;
+        isEmpty = true;
+    } else
+        ins = previous;
+
+    // Process from the start instruction
+    while (ins && ins != pos) {
+        if (isLoopStart(ins) || isIfStart(ins)) {
+            do {
+                bool write;
+                Compiler::StaticType type = listTypeAfterBranch(list, ins, previousType, isEmpty, pos, write, listTypes, visitedInstructions);
+
+                // If this branch contains the query point, return the final type
+                if (ins == firstBranch.first)
+                    return type;
+
+                // If there was a write, the list is no longer empty
+                if (write) {
+                    isEmpty = false;
+
+                    // The write could change the type
+                    if (!typesMatch(type, previousType))
+                        previousType = type;
+                }
+
+                // Skip the branch
+                ins = branchEnd(ins);
+            } while (isElse(ins)); // handle else branch
+        } else if (isListWrite(ins, list)) {
+            // List write instruction
+            Compiler::StaticType writeType = writeValueType(ins, listTypes, visitedInstructions);
+
+            if (!handleListWrite(writeType, previousType, isEmpty))
+                return Compiler::StaticType::Unknown;
+        }
+
+        ins = ins->next;
+    }
+
+    assert(ins);
+    return previousType;
+}
+
+Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch(
+    List *list,
+    LLVMInstruction *start,
+    Compiler::StaticType previousType,
+    bool isEmpty,
+    LLVMInstruction *query,
+    bool &write,
+    std::unordered_map<List *, Compiler::StaticType> listTypes,
+    InstructionSet &visitedInstructions) const
+{
     write = false;
 
+    if (!list || !start)
+        return previousType;
+
+    assert(isLoopStart(start) || isIfStart(start) || isElse(start));
+
+    bool isLoop = isLoopStart(start);
+    bool clearBeforeQueryPoint = false;
+    LLVMInstruction *ins = start->next;
+
     while (ins && !(isLoopEnd(ins) || isIfEnd(ins) || isElse(ins))) {
         if (isLoopStart(ins) || isIfStart(ins)) {
             do {
-                Compiler::StaticType type = listTypeAfterBranch(list, ins, previousType, isEmpty, query, write);
+                Compiler::StaticType type = listTypeAfterBranch(list, ins, previousType, isEmpty, query, write, listTypes, visitedInstructions);
 
                 // If there was a write, the list is no longer empty
                 if (write) {
@@ -309,7 +344,7 @@ Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch(List *list, LLVMInstr
             } while (isElse(ins)); // handle else branch
         } else if (isListWrite(ins, list)) {
             // List write instruction
-            Compiler::StaticType writeType = writeValueType(ins, visitedInstructions);
+            Compiler::StaticType writeType = writeValueType(ins, listTypes, visitedInstructions);
             write = true;
 
             if (!handleListWrite(writeType, previousType, isEmpty))
@@ -317,9 +352,14 @@ Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch(List *list, LLVMInstr
         } else if (isListClear(ins, list)) {
             // The list is now empty
             isEmpty = true;
+            clearBeforeQueryPoint = true;
             write = false; // the write variable is only used to check if the list is still empty
-        } else if (ins == query)
-            break;
+        } else if (ins == query) {
+            if (!isLoop || clearBeforeQueryPoint)
+                break;
+
+            clearBeforeQueryPoint = false;
+        }
 
         ins = ins->next;
     }
@@ -429,6 +469,11 @@ bool LLVMTypeAnalyzer::isVariableWrite(LLVMInstruction *ins, Variable *var) cons
     return (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == var);
 }
 
+bool LLVMTypeAnalyzer::isListRead(LLVMInstruction *ins) const
+{
+    return (ins->type == LLVMInstruction::Type::GetListItem);
+}
+
 bool LLVMTypeAnalyzer::isListWrite(LLVMInstruction *ins, List *list) const
 {
     return (LIST_WRITE_INSTRUCTIONS.find(ins->type) != LIST_WRITE_INSTRUCTIONS.cend() && ins->workList == list);
@@ -470,7 +515,7 @@ bool LLVMTypeAnalyzer::isWriteNoOp(LLVMInstruction *ins) const
     return false;
 }
 
-Compiler::StaticType LLVMTypeAnalyzer::writeValueType(LLVMInstruction *ins, InstructionSet &visitedInstructions) const
+Compiler::StaticType LLVMTypeAnalyzer::writeValueType(LLVMInstruction *ins, std::unordered_map<List *, Compiler::StaticType> listTypes, InstructionSet &visitedInstructions) const
 {
     assert(ins);
     assert(!ins->args.empty());
@@ -480,7 +525,17 @@ Compiler::StaticType LLVMTypeAnalyzer::writeValueType(LLVMInstruction *ins, Inst
         // TODO: Handle list item
         if (isVariableRead(arg->instruction.get())) {
             // If this is a variable read instruction, recursively get the variable type
-            return variableType(arg->instruction->workVariable, arg->instruction.get(), Compiler::StaticType::Unknown, visitedInstructions);
+            return variableType(arg->instruction->workVariable, arg->instruction.get(), Compiler::StaticType::Unknown, listTypes, visitedInstructions);
+        } else if (isListRead(arg->instruction.get())) {
+            // If this is a list read instruction, recursively get the list type
+            Compiler::StaticType type = Compiler::StaticType::Unknown;
+            auto it = listTypes.find(arg->instruction->workList);
+
+            if (it != listTypes.cend())
+                type = it->second;
+
+            // NOTE: The isEmpty parameter is useless here
+            return listType(arg->instruction->workList, arg->instruction.get(), type, false, listTypes, visitedInstructions);
         } else {
             // The write argument already has the instruction return type
             return optimizeRegisterType(arg);
@@ -495,7 +550,7 @@ bool LLVMTypeAnalyzer::typesMatch(Compiler::StaticType a, Compiler::StaticType b
     return (a == b) && (a != Compiler::StaticType::Unknown);
 }
 
-bool LLVMTypeAnalyzer::writeTypesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType, InstructionSet &visitedInstructions) const
+bool LLVMTypeAnalyzer::writeTypesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType, std::unordered_map<List *, Compiler::StaticType> listTypes, InstructionSet &visitedInstructions) const
 {
-    return typesMatch(writeValueType(ins, visitedInstructions), expectedType);
+    return typesMatch(writeValueType(ins, listTypes, visitedInstructions), expectedType);
 }
diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.h b/src/engine/internal/llvm/llvmtypeanalyzer.h
index 35b49732..d5f965df 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.h
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.h
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: Apache-2.0
 
 #include <scratchcpp/compiler.h>
+#include <unordered_map>
 
 namespace libscratchcpp
 {
@@ -20,11 +21,33 @@ class LLVMTypeAnalyzer
     private:
         using InstructionSet = std::unordered_set<LLVMInstruction *>;
 
-        Compiler::StaticType variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const;
+        Compiler::StaticType
+        variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType, std::unordered_map<List *, Compiler::StaticType> listTypes, InstructionSet &visitedInstructions) const;
+
         Compiler::StaticType variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const;
-        Compiler::StaticType variableTypeAfterBranchFromEnd(Variable *var, LLVMInstruction *end, Compiler::StaticType previousType, bool &write, InstructionSet &visitedInstructions) const;
 
-        Compiler::StaticType listTypeAfterBranch(List *list, LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty, LLVMInstruction *query, bool &write) const;
+        Compiler::StaticType variableTypeAfterBranchFromEnd(
+            Variable *var,
+            LLVMInstruction *end,
+            Compiler::StaticType previousType,
+            bool &write,
+            std::unordered_map<List *, Compiler::StaticType> listTypes,
+            InstructionSet &visitedInstructions) const;
+
+        Compiler::StaticType
+        listType(List *list, LLVMInstruction *pos, Compiler::StaticType previousType, bool isEmpty, std::unordered_map<List *, Compiler::StaticType> listTypes, InstructionSet &visitedInstructions)
+            const;
+
+        Compiler::StaticType listTypeAfterBranch(
+            List *list,
+            LLVMInstruction *start,
+            Compiler::StaticType previousType,
+            bool isEmpty,
+            LLVMInstruction *query,
+            bool &write,
+            std::unordered_map<List *, Compiler::StaticType> listTypes,
+            InstructionSet &visitedInstructions) const;
+
         bool handleListWrite(Compiler::StaticType writeType, Compiler::StaticType &previousType, bool &isEmpty) const;
 
         LLVMInstruction *branchEnd(LLVMInstruction *start) const;
@@ -39,14 +62,15 @@ class LLVMTypeAnalyzer
         bool isVariableRead(LLVMInstruction *ins) const;
         bool isVariableWrite(LLVMInstruction *ins, Variable *var) const;
 
+        bool isListRead(LLVMInstruction *ins) const;
         bool isListWrite(LLVMInstruction *ins, List *list) const;
         bool isListClear(LLVMInstruction *ins, List *list) const;
 
         Compiler::StaticType optimizeRegisterType(LLVMRegister *reg) const;
         bool isWriteNoOp(LLVMInstruction *ins) const;
-        Compiler::StaticType writeValueType(LLVMInstruction *ins, InstructionSet &visitedInstructions) const;
+        Compiler::StaticType writeValueType(LLVMInstruction *ins, std::unordered_map<List *, Compiler::StaticType> listTypes, InstructionSet &visitedInstructions) const;
         bool typesMatch(Compiler::StaticType a, Compiler::StaticType b) const;
-        bool writeTypesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType, InstructionSet &visitedInstructions) const;
+        bool writeTypesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType, std::unordered_map<List *, Compiler::StaticType> listTypes, InstructionSet &visitedInstructions) const;
 };
 
 } // namespace libscratchcpp
diff --git a/test/llvm/type_analyzer/listtype_test.cpp b/test/llvm/type_analyzer/listtype_test.cpp
index baf94722..e44cf825 100644
--- a/test/llvm/type_analyzer/listtype_test.cpp
+++ b/test/llvm/type_analyzer/listtype_test.cpp
@@ -2651,6 +2651,44 @@ TEST(LLVMTypeAnalyzer_ListType, ComplexMixedOperations_InLoop)
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, true), Compiler::StaticType::Unknown);
 }
 
+TEST(LLVMTypeAnalyzer_ListType, MultipleClearsInLoop)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "test");
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 5);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(appendList2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Bool, false), Compiler::StaticType::String);
+}
+
 TEST(LLVMTypeAnalyzer_ListType, ClearAndRebuild_WithDifferentTypes)
 {
     LLVMTypeAnalyzer analyzer;
@@ -3371,3 +3409,599 @@ TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_AppendToEmptyListAndClearInElseB
     // Should return String because the list remains empty after the if statement
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String);
 }
+
+TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_SimpleRead_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List sourceList("source", "");
+    List targetList("target", "");
+
+    // Establish source list type
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &sourceList;
+    instructionList.addInstruction(clearList);
+
+    auto appendSource = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister sourceValue(Compiler::StaticType::String, "hello");
+    appendSource->workList = &sourceList;
+    appendSource->args.push_back({ Compiler::StaticType::Unknown, &sourceValue });
+    instructionList.addInstruction(appendSource);
+
+    // Read from source list and write to target list
+    auto readSource = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readSourceReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    readSourceReg->instruction = readSource;
+    readSourceReg->isRawValue = false;
+    readSource->functionReturnReg = readSourceReg.get();
+    LLVMConstantRegister index(Compiler::StaticType::Number, 0);
+    readSource->workList = &sourceList;
+    readSource->args.push_back({ Compiler::StaticType::Number, &index });
+    instructionList.addInstruction(readSource);
+
+    auto appendTarget = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    appendTarget->workList = &targetList;
+    appendTarget->args.push_back({ Compiler::StaticType::Unknown, readSourceReg.get() });
+    instructionList.addInstruction(appendTarget);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(&targetList, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_SimpleRead_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List sourceList("source", "");
+    List targetList("target", "");
+
+    // Establish source list type
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &sourceList;
+    instructionList.addInstruction(clearList);
+
+    auto appendSource = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister sourceValue(Compiler::StaticType::Bool, true);
+    appendSource->workList = &sourceList;
+    appendSource->args.push_back({ Compiler::StaticType::Unknown, &sourceValue });
+    instructionList.addInstruction(appendSource);
+
+    // Read from source list and write to target list
+    auto readSource = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readSourceReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    readSourceReg->instruction = readSource;
+    readSourceReg->isRawValue = false;
+    readSource->functionReturnReg = readSourceReg.get();
+    LLVMConstantRegister index(Compiler::StaticType::Number, 0);
+    readSource->workList = &sourceList;
+    readSource->args.push_back({ Compiler::StaticType::Number, &index });
+    instructionList.addInstruction(readSource);
+
+    auto appendTarget = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    appendTarget->workList = &targetList;
+    appendTarget->args.push_back({ Compiler::StaticType::Unknown, readSourceReg.get() });
+    instructionList.addInstruction(appendTarget);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(&targetList, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Bool);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_InLoop_TypeConflict)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List sourceList("source", "");
+    List targetList("target", "");
+
+    auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(loopStart);
+
+    // Clear source list
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &sourceList;
+    instructionList.addInstruction(clearList);
+
+    // First iteration: append string to source
+    auto appendSource1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister sourceValue1(Compiler::StaticType::String, "text");
+    appendSource1->workList = &sourceList;
+    appendSource1->args.push_back({ Compiler::StaticType::Unknown, &sourceValue1 });
+    instructionList.addInstruction(appendSource1);
+
+    // Read from source and write to target
+    auto readSource1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readSource1Reg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    readSource1Reg->instruction = readSource1;
+    readSource1Reg->isRawValue = false;
+    readSource1->functionReturnReg = readSource1Reg.get();
+    LLVMConstantRegister index1(Compiler::StaticType::Number, 0);
+    readSource1->workList = &sourceList;
+    readSource1->args.push_back({ Compiler::StaticType::Number, &index1 });
+    instructionList.addInstruction(readSource1);
+
+    auto appendTarget1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    appendTarget1->workList = &targetList;
+    appendTarget1->args.push_back({ Compiler::StaticType::Unknown, readSource1Reg.get() });
+    instructionList.addInstruction(appendTarget1);
+
+    // Second iteration: append number to source (creates type conflict)
+    auto appendSource2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister sourceValue2(Compiler::StaticType::Number, 42);
+    appendSource2->workList = &sourceList;
+    appendSource2->args.push_back({ Compiler::StaticType::Unknown, &sourceValue2 });
+    instructionList.addInstruction(appendSource2);
+
+    // Read from source and write to target
+    auto readSource2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readSource2Reg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    readSource2Reg->instruction = readSource2;
+    readSource2Reg->isRawValue = false;
+    readSource2->functionReturnReg = readSource2Reg.get();
+    LLVMConstantRegister index2(Compiler::StaticType::Number, 1);
+    readSource2->workList = &sourceList;
+    readSource2->args.push_back({ Compiler::StaticType::Number, &index2 });
+    instructionList.addInstruction(readSource2);
+
+    auto appendTarget2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    appendTarget2->workList = &targetList;
+    appendTarget2->args.push_back({ Compiler::StaticType::Unknown, readSource2Reg.get() });
+    instructionList.addInstruction(appendTarget2);
+
+    auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(loopEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(&targetList, funcCall.get(), Compiler::StaticType::String, true), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_InLoop_ConsistentType_NonEmptySource)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List sourceList("source", "");
+    List targetList("target", "");
+
+    auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(loopStart);
+
+    // Append number to source
+    auto appendSource = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister sourceValue(Compiler::StaticType::Number, 3.14);
+    appendSource->workList = &sourceList;
+    appendSource->args.push_back({ Compiler::StaticType::Unknown, &sourceValue });
+    instructionList.addInstruction(appendSource);
+
+    // Read from source and write to target
+    auto readSource = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readSourceReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    readSourceReg->instruction = readSource;
+    readSourceReg->isRawValue = false;
+    readSource->functionReturnReg = readSourceReg.get();
+    LLVMConstantRegister index(Compiler::StaticType::Number, 0);
+    readSource->workList = &sourceList;
+    readSource->args.push_back({ Compiler::StaticType::Number, &index });
+    instructionList.addInstruction(readSource);
+
+    auto appendTarget = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    appendTarget->workList = &targetList;
+    appendTarget->args.push_back({ Compiler::StaticType::Unknown, readSourceReg.get() });
+    instructionList.addInstruction(appendTarget);
+
+    auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(loopEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(&targetList, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_InLoop_ConsistentType_EmptySource)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List sourceList("source", "");
+    List targetList("target", "");
+
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &sourceList;
+    instructionList.addInstruction(clearList);
+
+    auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(loopStart);
+
+    // Append number to source
+    auto appendSource = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister sourceValue(Compiler::StaticType::Number, 3.14);
+    appendSource->workList = &sourceList;
+    appendSource->args.push_back({ Compiler::StaticType::Unknown, &sourceValue });
+    instructionList.addInstruction(appendSource);
+
+    // Read from source and write to target
+    auto readSource = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readSourceReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    readSourceReg->instruction = readSource;
+    readSourceReg->isRawValue = false;
+    readSource->functionReturnReg = readSourceReg.get();
+    LLVMConstantRegister index(Compiler::StaticType::Number, 0);
+    readSource->workList = &sourceList;
+    readSource->args.push_back({ Compiler::StaticType::Number, &index });
+    instructionList.addInstruction(readSource);
+
+    auto appendTarget = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    appendTarget->workList = &targetList;
+    appendTarget->args.push_back({ Compiler::StaticType::Unknown, readSourceReg.get() });
+    instructionList.addInstruction(appendTarget);
+
+    auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(loopEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(&targetList, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_Circular_TypeSafety)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List listA("listA", "");
+    List listB("listB", "");
+
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &listA;
+    instructionList.addInstruction(clearList);
+
+    clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &listB;
+    instructionList.addInstruction(clearList);
+
+    // Initialize listA with a number
+    auto appendA1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister valueA1(Compiler::StaticType::Number, 10);
+    appendA1->workList = &listA;
+    appendA1->args.push_back({ Compiler::StaticType::Unknown, &valueA1 });
+    instructionList.addInstruction(appendA1);
+
+    // Read from listA and write to listB
+    auto readA = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readAReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    readAReg->instruction = readA;
+    readAReg->isRawValue = false;
+    readA->functionReturnReg = readAReg.get();
+    LLVMConstantRegister indexA(Compiler::StaticType::Number, 0);
+    readA->workList = &listA;
+    readA->args.push_back({ Compiler::StaticType::Number, &indexA });
+    instructionList.addInstruction(readA);
+
+    auto appendB = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    appendB->workList = &listB;
+    appendB->args.push_back({ Compiler::StaticType::Unknown, readAReg.get() });
+    instructionList.addInstruction(appendB);
+
+    // Read from listB and write back to listA (circular dependency)
+    auto readB = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readBReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    readBReg->instruction = readB;
+    readBReg->isRawValue = false;
+    readB->functionReturnReg = readBReg.get();
+    LLVMConstantRegister indexB(Compiler::StaticType::Number, 0);
+    readB->workList = &listB;
+    readB->args.push_back({ Compiler::StaticType::Number, &indexB });
+    instructionList.addInstruction(readB);
+
+    auto appendA2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    appendA2->workList = &listA;
+    appendA2->args.push_back({ Compiler::StaticType::Unknown, readBReg.get() });
+    instructionList.addInstruction(appendA2);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(&listA, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_Circular_TypeSafety_InLoop)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List listA("listA", "");
+    List listB("listB", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &listA;
+    instructionList.addInstruction(clearList);
+
+    clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &listB;
+    instructionList.addInstruction(clearList);
+
+    // Initialize listA with a number
+    auto appendA1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister valueA1(Compiler::StaticType::Number, 10);
+    appendA1->workList = &listA;
+    appendA1->args.push_back({ Compiler::StaticType::Unknown, &valueA1 });
+    instructionList.addInstruction(appendA1);
+
+    // Read from listA and write to listB
+    auto readA = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readAReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    readAReg->instruction = readA;
+    readAReg->isRawValue = false;
+    readA->functionReturnReg = readAReg.get();
+    LLVMConstantRegister indexA(Compiler::StaticType::Number, 0);
+    readA->workList = &listA;
+    readA->args.push_back({ Compiler::StaticType::Number, &indexA });
+    instructionList.addInstruction(readA);
+
+    auto appendB = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    appendB->workList = &listB;
+    appendB->args.push_back({ Compiler::StaticType::Unknown, readAReg.get() });
+    instructionList.addInstruction(appendB);
+
+    // Read from listB and write back to listA (circular dependency)
+    auto readB = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readBReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    readBReg->instruction = readB;
+    readBReg->isRawValue = false;
+    readB->functionReturnReg = readBReg.get();
+    LLVMConstantRegister indexB(Compiler::StaticType::Number, 0);
+    readB->workList = &listB;
+    readB->args.push_back({ Compiler::StaticType::Number, &indexB });
+    instructionList.addInstruction(readB);
+
+    auto appendA2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    appendA2->workList = &listA;
+    appendA2->args.push_back({ Compiler::StaticType::Unknown, readBReg.get() });
+    instructionList.addInstruction(appendA2);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listType(&listA, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_Circular_TypeConflict)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List listA("listA", "");
+    List listB("listB", "");
+
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &listA;
+    instructionList.addInstruction(clearList);
+
+    clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &listB;
+    instructionList.addInstruction(clearList);
+
+    auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(loopStart);
+
+    // Initialize listA with a number
+    auto appendA1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister valueA1(Compiler::StaticType::Number, 10);
+    appendA1->workList = &listA;
+    appendA1->args.push_back({ Compiler::StaticType::Unknown, &valueA1 });
+    instructionList.addInstruction(appendA1);
+
+    // Read from listA and write to listB
+    auto readA = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readAReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    readAReg->instruction = readA;
+    readAReg->isRawValue = false;
+    readA->functionReturnReg = readAReg.get();
+    LLVMConstantRegister indexA(Compiler::StaticType::Number, 0);
+    readA->workList = &listA;
+    readA->args.push_back({ Compiler::StaticType::Number, &indexA });
+    instructionList.addInstruction(readA);
+
+    auto appendB = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    appendB->workList = &listB;
+    appendB->args.push_back({ Compiler::StaticType::Unknown, readAReg.get() });
+    instructionList.addInstruction(appendB);
+
+    // Create type conflict by appending string to listB
+    auto appendB2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister valueB2(Compiler::StaticType::String, "conflict");
+    appendB2->workList = &listB;
+    appendB2->args.push_back({ Compiler::StaticType::Unknown, &valueB2 });
+    instructionList.addInstruction(appendB2);
+
+    // Read from listB and write back to listA (circular dependency with type conflict)
+    auto readB = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readBReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    readBReg->instruction = readB;
+    readBReg->isRawValue = false;
+    readB->functionReturnReg = readBReg.get();
+    LLVMConstantRegister indexB(Compiler::StaticType::Number, 0);
+    readB->workList = &listB;
+    readB->args.push_back({ Compiler::StaticType::Number, &indexB });
+    instructionList.addInstruction(readB);
+
+    auto appendA2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    appendA2->workList = &listA;
+    appendA2->args.push_back({ Compiler::StaticType::Unknown, readBReg.get() });
+    instructionList.addInstruction(appendA2);
+
+    auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(loopEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should return Unknown due to circular dependency with type conflicts
+    ASSERT_EQ(analyzer.listType(&listA, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_Circular_SingleList_KnownType_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    // Initialize list with a number
+    auto append1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 10);
+    append1->workList = &list;
+    append1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(append1);
+
+    // Read from list and write to list
+    auto read = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    readReg->instruction = read;
+    readReg->isRawValue = false;
+    read->functionReturnReg = readReg.get();
+    LLVMConstantRegister index(Compiler::StaticType::Number, 0);
+    read->workList = &list;
+    read->args.push_back({ Compiler::StaticType::Number, &index });
+    instructionList.addInstruction(read);
+
+    auto append2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    append2->workList = &list;
+    append2->args.push_back({ Compiler::StaticType::Unknown, readReg.get() });
+    instructionList.addInstruction(append2);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_Circular_SingleList_KnownType_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // Read from list and write to list
+    auto read = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    readReg->instruction = read;
+    readReg->isRawValue = false;
+    read->functionReturnReg = readReg.get();
+    LLVMConstantRegister index(Compiler::StaticType::Number, 0);
+    read->workList = &list;
+    read->args.push_back({ Compiler::StaticType::Number, &index });
+    instructionList.addInstruction(read);
+
+    auto append2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    append2->workList = &list;
+    append2->args.push_back({ Compiler::StaticType::Unknown, readReg.get() });
+    instructionList.addInstruction(append2);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_Circular_SingleList_UnknownType)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    // Read from list and write to list
+    auto read = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    readReg->instruction = read;
+    readReg->isRawValue = false;
+    read->functionReturnReg = readReg.get();
+    LLVMConstantRegister index(Compiler::StaticType::Number, 0);
+    read->workList = &list;
+    read->args.push_back({ Compiler::StaticType::Number, &index });
+    instructionList.addInstruction(read);
+
+    auto append2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    append2->workList = &list;
+    append2->args.push_back({ Compiler::StaticType::Unknown, readReg.get() });
+    instructionList.addInstruction(append2);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Unknown, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_ChainedReads_TypePropagation)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List listA("listA", "");
+    List listB("listB", "");
+    List listC("listC", "");
+
+    // Clear lists
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &listA;
+    instructionList.addInstruction(clearList);
+
+    clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &listB;
+    instructionList.addInstruction(clearList);
+
+    // Initialize listA with a boolean
+    auto appendA = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister valueA(Compiler::StaticType::Bool, false);
+    appendA->workList = &listA;
+    appendA->args.push_back({ Compiler::StaticType::Unknown, &valueA });
+    instructionList.addInstruction(appendA);
+
+    // Read from listA and write to listB
+    auto readA = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readAReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    readAReg->instruction = readA;
+    readAReg->isRawValue = false;
+    readA->functionReturnReg = readAReg.get();
+    LLVMConstantRegister indexA(Compiler::StaticType::Number, 0);
+    readA->workList = &listA;
+    readA->args.push_back({ Compiler::StaticType::Number, &indexA });
+    instructionList.addInstruction(readA);
+
+    auto appendB = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    appendB->workList = &listB;
+    appendB->args.push_back({ Compiler::StaticType::Unknown, readAReg.get() });
+    instructionList.addInstruction(appendB);
+
+    // Read from listB and write to listC
+    auto readB = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readBReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    readBReg->instruction = readB;
+    readBReg->isRawValue = false;
+    readB->functionReturnReg = readBReg.get();
+    LLVMConstantRegister indexB(Compiler::StaticType::Number, 0);
+    readB->workList = &listB;
+    readB->args.push_back({ Compiler::StaticType::Number, &indexB });
+    instructionList.addInstruction(readB);
+
+    auto appendC = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    appendC->workList = &listC;
+    appendC->args.push_back({ Compiler::StaticType::Unknown, readBReg.get() });
+    instructionList.addInstruction(appendC);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Type should propagate through the chain: A -> B -> C
+    ASSERT_EQ(analyzer.listType(&listC, funcCall.get(), Compiler::StaticType::String, true), Compiler::StaticType::Bool);
+}
diff --git a/test/llvm/type_analyzer/listtypeafterbranch_test.cpp b/test/llvm/type_analyzer/listtypeafterbranch_test.cpp
index 8169e875..5da22fd2 100644
--- a/test/llvm/type_analyzer/listtypeafterbranch_test.cpp
+++ b/test/llvm/type_analyzer/listtypeafterbranch_test.cpp
@@ -2371,3 +2371,308 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_AppendToEmptyListAndC
     // Should return String because the list remains empty after the if statement
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String);
 }
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CrossListDependency_ReadFromTypedList)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List sourceList("", "");
+    List targetList("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // Clear sourceList
+    auto clear = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clear->workList = &sourceList;
+    instructionList.addInstruction(clear);
+
+    // Set sourceList type
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &sourceList;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Read from sourceList
+    auto getItem = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    LLVMConstantRegister index(Compiler::StaticType::Number, 0);
+    getItem->workList = &sourceList;
+    getItem->args.push_back({ Compiler::StaticType::Number, &index });
+    auto itemRegister = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    itemRegister->instruction = getItem;
+    itemRegister->isRawValue = false;
+    getItem->functionReturnReg = itemRegister.get();
+    instructionList.addInstruction(getItem);
+
+    // Append the read value to targetList
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    appendList2->workList = &targetList;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, itemRegister.get() });
+    instructionList.addInstruction(appendList2);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Target list type depends on source list type
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&targetList, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CrossListDependency_ReadFromUnknownList)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List sourceList("", "");
+    List targetList("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // Read from sourceList
+    auto getItem = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    LLVMConstantRegister index(Compiler::StaticType::Number, 0);
+    getItem->workList = &sourceList;
+    getItem->args.push_back({ Compiler::StaticType::Number, &index });
+    auto itemRegister = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    itemRegister->instruction = getItem;
+    itemRegister->isRawValue = false;
+    getItem->functionReturnReg = itemRegister.get();
+    instructionList.addInstruction(getItem);
+
+    // Append the read value to targetList
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    appendList->workList = &targetList;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, itemRegister.get() });
+    instructionList.addInstruction(appendList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&targetList, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CrossListDependency_ChainedReads_KnownType)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list1("", "");
+    List list2("", "");
+    List list3("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // Clear list1
+    auto clear = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clear->workList = &list1;
+    instructionList.addInstruction(clear);
+
+    // Clear list2
+    clear = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clear->workList = &list2;
+    instructionList.addInstruction(clear);
+
+    // Set list1 type
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
+    appendList1->workList = &list1;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(appendList1);
+
+    // Read from list1
+    auto getItem1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    LLVMConstantRegister index1(Compiler::StaticType::Number, 0);
+    getItem1->workList = &list1;
+    getItem1->args.push_back({ Compiler::StaticType::Number, &index1 });
+    auto itemRegister1 = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    itemRegister1->instruction = getItem1;
+    itemRegister1->isRawValue = false;
+    getItem1->functionReturnReg = itemRegister1.get();
+    instructionList.addInstruction(getItem1);
+
+    // Append to list2
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    appendList2->workList = &list2;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, itemRegister1.get() });
+    instructionList.addInstruction(appendList2);
+
+    // Read from list2
+    auto getItem2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    LLVMConstantRegister index2(Compiler::StaticType::Number, 0);
+    getItem2->workList = &list2;
+    getItem2->args.push_back({ Compiler::StaticType::Number, &index2 });
+    auto itemRegister2 = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    itemRegister2->instruction = getItem2;
+    itemRegister2->isRawValue = false;
+    getItem2->functionReturnReg = itemRegister2.get();
+    instructionList.addInstruction(getItem2);
+
+    // Append to list3
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    appendList3->workList = &list3;
+    appendList3->args.push_back({ Compiler::StaticType::Unknown, itemRegister2.get() });
+    instructionList.addInstruction(appendList3);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list3, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CrossListDependency_ChainedReads_UnknownType)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list1("", "");
+    List list2("", "");
+    List list3("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // Read from list1
+    auto getItem1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    LLVMConstantRegister index1(Compiler::StaticType::Number, 0);
+    getItem1->workList = &list1;
+    getItem1->args.push_back({ Compiler::StaticType::Number, &index1 });
+    auto itemRegister1 = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    itemRegister1->instruction = getItem1;
+    itemRegister1->isRawValue = false;
+    getItem1->functionReturnReg = itemRegister1.get();
+    instructionList.addInstruction(getItem1);
+
+    // Append to list2
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    appendList2->workList = &list2;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, itemRegister1.get() });
+    instructionList.addInstruction(appendList2);
+
+    // Read from list2
+    auto getItem2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    LLVMConstantRegister index2(Compiler::StaticType::Number, 0);
+    getItem2->workList = &list2;
+    getItem2->args.push_back({ Compiler::StaticType::Number, &index2 });
+    auto itemRegister2 = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    itemRegister2->instruction = getItem2;
+    itemRegister2->isRawValue = false;
+    getItem2->functionReturnReg = itemRegister2.get();
+    instructionList.addInstruction(getItem2);
+
+    // Append to list3
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    appendList3->workList = &list3;
+    appendList3->args.push_back({ Compiler::StaticType::Unknown, itemRegister2.get() });
+    instructionList.addInstruction(appendList3);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // list3 should have Unknown type due to chained cross-list dependencies
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&list3, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CrossListDependency_ConditionalRead)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List sourceList("", "");
+    List targetList("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // If statement
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // Read from sourceList in if branch
+    auto getItem = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    LLVMConstantRegister index(Compiler::StaticType::Number, 0);
+    getItem->workList = &sourceList;
+    getItem->args.push_back({ Compiler::StaticType::Number, &index });
+    auto itemRegister = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    itemRegister->instruction = getItem;
+    itemRegister->isRawValue = false;
+    getItem->functionReturnReg = itemRegister.get();
+    instructionList.addInstruction(getItem);
+
+    // Append to targetList
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    appendList->workList = &targetList;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, itemRegister.get() });
+    instructionList.addInstruction(appendList);
+
+    // Else branch
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    // Direct append of constant value
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister directValue(Compiler::StaticType::Number, 42);
+    appendList2->workList = &targetList;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &directValue });
+    instructionList.addInstruction(appendList2);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Should return Unknown due to cross-list dependency and conditional execution
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&targetList, start.get(), Compiler::StaticType::String, true), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CrossListDependency_ReadWithInsertAndReplace)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List sourceList("", "");
+    List targetList("", "");
+
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(start);
+
+    // Read from sourceList
+    auto getItem = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    LLVMConstantRegister index(Compiler::StaticType::Number, 0);
+    getItem->workList = &sourceList;
+    getItem->args.push_back({ Compiler::StaticType::Number, &index });
+    auto itemRegister = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    itemRegister->instruction = getItem;
+    itemRegister->isRawValue = false;
+    getItem->functionReturnReg = itemRegister.get();
+    instructionList.addInstruction(getItem);
+
+    // Insert the read value to targetList
+    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    LLVMConstantRegister insertIndex(Compiler::StaticType::Number, 0);
+    insertList->workList = &targetList;
+    insertList->args.push_back({ Compiler::StaticType::Number, &insertIndex });
+    insertList->args.push_back({ Compiler::StaticType::Unknown, itemRegister.get() });
+    instructionList.addInstruction(insertList);
+
+    // Replace with another read from the same list
+    auto getItem2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    LLVMConstantRegister index2(Compiler::StaticType::Number, 1);
+    getItem2->workList = &sourceList;
+    getItem2->args.push_back({ Compiler::StaticType::Number, &index2 });
+    auto itemRegister2 = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    itemRegister2->instruction = getItem2;
+    itemRegister2->isRawValue = false;
+    getItem2->functionReturnReg = itemRegister2.get();
+    instructionList.addInstruction(getItem2);
+
+    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    LLVMConstantRegister replaceIndex(Compiler::StaticType::Number, 0);
+    replaceList->workList = &targetList;
+    replaceList->args.push_back({ Compiler::StaticType::Number, &replaceIndex });
+    replaceList->args.push_back({ Compiler::StaticType::Unknown, itemRegister2.get() });
+    instructionList.addInstruction(replaceList);
+
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(end);
+
+    // Should have Unknown type due to cross-list dependencies
+    ASSERT_EQ(analyzer.listTypeAfterBranch(&targetList, start.get(), Compiler::StaticType::String, true), Compiler::StaticType::Unknown);
+}

From ae4690a51c24b669c6ca69f37b3ad8e6c547ec3c Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Fri, 1 Aug 2025 15:16:43 +0200
Subject: [PATCH 45/79] Add mixed test suite for LLVMTypeAnalyzer

---
 test/llvm/CMakeLists.txt               |   1 +
 test/llvm/type_analyzer/mixed_test.cpp | 492 +++++++++++++++++++++++++
 2 files changed, 493 insertions(+)
 create mode 100644 test/llvm/type_analyzer/mixed_test.cpp

diff --git a/test/llvm/CMakeLists.txt b/test/llvm/CMakeLists.txt
index 95330a1d..e5bd2c39 100644
--- a/test/llvm/CMakeLists.txt
+++ b/test/llvm/CMakeLists.txt
@@ -24,6 +24,7 @@ add_executable(
   type_analyzer/variabletype_test.cpp
   type_analyzer/listtypeafterbranch_test.cpp
   type_analyzer/listtype_test.cpp
+  type_analyzer/mixed_test.cpp
 )
 
 target_link_libraries(
diff --git a/test/llvm/type_analyzer/mixed_test.cpp b/test/llvm/type_analyzer/mixed_test.cpp
new file mode 100644
index 00000000..9ef3fc95
--- /dev/null
+++ b/test/llvm/type_analyzer/mixed_test.cpp
@@ -0,0 +1,492 @@
+#include <scratchcpp/variable.h>
+#include <scratchcpp/list.h>
+#include <engine/internal/llvm/llvmtypeanalyzer.h>
+#include <engine/internal/llvm/llvminstruction.h>
+#include <engine/internal/llvm/llvminstructionlist.h>
+#include <engine/internal/llvm/llvmconstantregister.h>
+#include <gtest/gtest.h>
+
+using namespace libscratchcpp;
+
+TEST(LLVMTypeAnalyzer_MixedTest, VariableToList_SimpleTransfer_NonEmpty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    Variable sourceVar("sourceVar", "");
+    List targetList("targetList", "");
+
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &targetList;
+    instructionList.addInstruction(clearList);
+
+    // Write to variable
+    auto writeVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister varValue(Compiler::StaticType::String, "hello");
+    writeVar->workVariable = &sourceVar;
+    writeVar->args.push_back({ Compiler::StaticType::Unknown, &varValue });
+    instructionList.addInstruction(writeVar);
+
+    // Read from variable and write to list
+    auto readVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVarReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    readVar->functionReturnReg = readVarReg.get();
+    readVarReg->instruction = readVar;
+    readVar->workVariable = &sourceVar;
+    instructionList.addInstruction(readVar);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    appendList->workList = &targetList;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, readVarReg.get() });
+    instructionList.addInstruction(appendList);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // List type should match variable type
+    ASSERT_EQ(analyzer.listType(&targetList, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_MixedTest, ListToVariable_SimpleTransfer_Empty)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List sourceList("sourceList", "");
+    Variable targetVar("targetVar", "");
+
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &sourceList;
+    instructionList.addInstruction(clearList);
+
+    // Write to list
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister listValue(Compiler::StaticType::Bool, true);
+    appendList->workList = &sourceList;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &listValue });
+    instructionList.addInstruction(appendList);
+
+    // Read from list and write to variable
+    auto readList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readListReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    readList->functionReturnReg = readListReg.get();
+    readListReg->instruction = readList;
+    LLVMConstantRegister index(Compiler::StaticType::Number, 0);
+    readList->workList = &sourceList;
+    readList->args.push_back({ Compiler::StaticType::Number, &index });
+    instructionList.addInstruction(readList);
+
+    auto writeVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    writeVar->workVariable = &targetVar;
+    writeVar->args.push_back({ Compiler::StaticType::Unknown, readListReg.get() });
+    instructionList.addInstruction(writeVar);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Variable type should match list type
+    ASSERT_EQ(analyzer.variableType(&targetVar, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Bool);
+}
+
+TEST(LLVMTypeAnalyzer_MixedTest, CircularVarListDependency_TypeSafety)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    Variable var("var", "");
+    List list("list", "");
+
+    // Initialize variable with number
+    auto writeVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
+    writeVar1->workVariable = &var;
+    writeVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(writeVar1);
+
+    // Read from variable and write to list
+    auto readVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVarReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    readVar->functionReturnReg = readVarReg.get();
+    readVarReg->instruction = readVar;
+    readVar->workVariable = &var;
+    instructionList.addInstruction(readVar);
+
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, readVarReg.get() });
+    instructionList.addInstruction(appendList);
+
+    // Read from list and write back to variable (circular dependency)
+    auto readList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readListReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    readList->functionReturnReg = readListReg.get();
+    readListReg->instruction = readList;
+    LLVMConstantRegister index(Compiler::StaticType::Number, 0);
+    readList->workList = &list;
+    readList->args.push_back({ Compiler::StaticType::Number, &index });
+    instructionList.addInstruction(readList);
+
+    auto writeVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    writeVar2->workVariable = &var;
+    writeVar2->args.push_back({ Compiler::StaticType::Unknown, readListReg.get() });
+    instructionList.addInstruction(writeVar2);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should handle circular dependency gracefully
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_MixedTest, LoopWithVarListInteraction_TypeConflict)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    Variable var("var", "");
+    List list("list", "");
+
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    // First iteration: write string to variable
+    auto writeVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::String, "text");
+    writeVar1->workVariable = &var;
+    writeVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(writeVar1);
+
+    auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(loopStart);
+
+    // Read from variable and write to list
+    auto readVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVarReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    readVar->functionReturnReg = readVarReg.get();
+    readVarReg->instruction = readVar;
+    readVar->workVariable = &var;
+    instructionList.addInstruction(readVar);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, readVarReg.get() });
+    instructionList.addInstruction(appendList);
+
+    // Second iteration: write number to variable (creates type conflict)
+    auto writeVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Number, 42);
+    writeVar2->workVariable = &var;
+    writeVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(writeVar2);
+
+    auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(loopEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should return Unknown due to type conflict
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_MixedTest, ConditionalVarListTransfer_TypeConflict)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    Variable var("var", "");
+    List list("list", "");
+
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    instructionList.addInstruction(ifStart);
+
+    // If branch: write number to variable, transfer to list
+    auto writeVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Number, 123);
+    writeVar1->workVariable = &var;
+    writeVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(writeVar1);
+
+    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar1Reg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    readVar1->functionReturnReg = readVar1Reg.get();
+    readVar1Reg->instruction = readVar1;
+    readVar1->workVariable = &var;
+    instructionList.addInstruction(readVar1);
+
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, readVar1Reg.get() });
+    instructionList.addInstruction(appendList1);
+
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    instructionList.addInstruction(elseStart);
+
+    // Else branch: write string to variable, transfer to list
+    auto writeVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "hello");
+    writeVar2->workVariable = &var;
+    writeVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(writeVar2);
+
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar2Reg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    readVar2->functionReturnReg = readVar2Reg.get();
+    readVar2Reg->instruction = readVar2;
+    readVar2->workVariable = &var;
+    instructionList.addInstruction(readVar2);
+
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, readVar2Reg.get() });
+    instructionList.addInstruction(appendList2);
+
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    instructionList.addInstruction(ifEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should return Unknown due to conditional type conflicts
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
+}
+
+TEST(LLVMTypeAnalyzer_MixedTest, MultipleVarsToSingleList_TypePropagation)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    Variable var1("var1", "");
+    Variable var2("var2", "");
+    List list("list", "");
+
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    // Initialize first variable with boolean
+    auto writeVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Bool, true);
+    writeVar1->workVariable = &var1;
+    writeVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(writeVar1);
+
+    // Initialize second variable with same type
+    auto writeVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::Bool, false);
+    writeVar2->workVariable = &var2;
+    writeVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(writeVar2);
+
+    // Read from first variable and write to list
+    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar1Reg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    readVar1->functionReturnReg = readVar1Reg.get();
+    readVar1Reg->instruction = readVar1;
+    readVar1->workVariable = &var1;
+    instructionList.addInstruction(readVar1);
+
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    appendList1->workList = &list;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, readVar1Reg.get() });
+    instructionList.addInstruction(appendList1);
+
+    // Read from second variable and write to list
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar2Reg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    readVar2->functionReturnReg = readVar2Reg.get();
+    readVar2Reg->instruction = readVar2;
+    readVar2->workVariable = &var2;
+    instructionList.addInstruction(readVar2);
+
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    appendList2->workList = &list;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, readVar2Reg.get() });
+    instructionList.addInstruction(appendList2);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // List should have Bool type from both variables
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::Bool);
+}
+
+TEST(LLVMTypeAnalyzer_MixedTest, SingleListToMultipleVars_TypePropagation)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List sourceList("sourceList", "");
+    Variable var1("var1", "");
+    Variable var2("var2", "");
+
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &sourceList;
+    instructionList.addInstruction(clearList);
+
+    // Initialize list with string values
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister listValue1(Compiler::StaticType::String, "first");
+    appendList1->workList = &sourceList;
+    appendList1->args.push_back({ Compiler::StaticType::Unknown, &listValue1 });
+    instructionList.addInstruction(appendList1);
+
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister listValue2(Compiler::StaticType::String, "second");
+    appendList2->workList = &sourceList;
+    appendList2->args.push_back({ Compiler::StaticType::Unknown, &listValue2 });
+    instructionList.addInstruction(appendList2);
+
+    // Read first item and write to first variable
+    auto readList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readList1Reg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    readList1->functionReturnReg = readList1Reg.get();
+    readList1Reg->instruction = readList1;
+    LLVMConstantRegister index1(Compiler::StaticType::Number, 0);
+    readList1->workList = &sourceList;
+    readList1->args.push_back({ Compiler::StaticType::Number, &index1 });
+    instructionList.addInstruction(readList1);
+
+    auto writeVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    writeVar1->workVariable = &var1;
+    writeVar1->args.push_back({ Compiler::StaticType::Unknown, readList1Reg.get() });
+    instructionList.addInstruction(writeVar1);
+
+    // Read second item and write to second variable
+    auto readList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readList2Reg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    readList2->functionReturnReg = readList2Reg.get();
+    readList2Reg->instruction = readList2;
+    LLVMConstantRegister index2(Compiler::StaticType::Number, 1);
+    readList2->workList = &sourceList;
+    readList2->args.push_back({ Compiler::StaticType::Number, &index2 });
+    instructionList.addInstruction(readList2);
+
+    auto writeVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    writeVar2->workVariable = &var2;
+    writeVar2->args.push_back({ Compiler::StaticType::Unknown, readList2Reg.get() });
+    instructionList.addInstruction(writeVar2);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Both variables should have String type from the list
+    ASSERT_EQ(analyzer.variableType(&var1, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
+    ASSERT_EQ(analyzer.variableType(&var2, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
+}
+
+TEST(LLVMTypeAnalyzer_MixedTest, ComplexChain_VarToListToVar_TypePropagation)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    Variable sourceVar("sourceVar", "");
+    List intermediateList("intermediateList", "");
+    Variable targetVar("targetVar", "");
+
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &intermediateList;
+    instructionList.addInstruction(clearList);
+
+    // Initialize source variable
+    auto writeSourceVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister sourceValue(Compiler::StaticType::Number, 3.14159);
+    writeSourceVar->workVariable = &sourceVar;
+    writeSourceVar->args.push_back({ Compiler::StaticType::Unknown, &sourceValue });
+    instructionList.addInstruction(writeSourceVar);
+
+    // Read from source variable and write to intermediate list
+    auto readSourceVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readSourceVarReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    readSourceVar->functionReturnReg = readSourceVarReg.get();
+    readSourceVarReg->instruction = readSourceVar;
+    readSourceVar->workVariable = &sourceVar;
+    instructionList.addInstruction(readSourceVar);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    appendList->workList = &intermediateList;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, readSourceVarReg.get() });
+    instructionList.addInstruction(appendList);
+
+    // Read from intermediate list and write to target variable
+    auto readList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readListReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    readList->functionReturnReg = readListReg.get();
+    readListReg->instruction = readList;
+    LLVMConstantRegister index(Compiler::StaticType::Number, 0);
+    readList->workList = &intermediateList;
+    readList->args.push_back({ Compiler::StaticType::Number, &index });
+    instructionList.addInstruction(readList);
+
+    auto writeTargetVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    writeTargetVar->workVariable = &targetVar;
+    writeTargetVar->args.push_back({ Compiler::StaticType::Unknown, readListReg.get() });
+    instructionList.addInstruction(writeTargetVar);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Type should propagate through the chain: sourceVar -> intermediateList -> targetVar
+    ASSERT_EQ(analyzer.variableType(&targetVar, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Number);
+    ASSERT_EQ(analyzer.listType(&intermediateList, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::Number);
+}
+
+TEST(LLVMTypeAnalyzer_MixedTest, NestedLoopWithMixedDependencies_TypeConflict)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    Variable var("var", "");
+    List list("list", "");
+
+    auto outerLoopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(outerLoopStart);
+
+    // Write to variable in outer loop
+    auto writeVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value1(Compiler::StaticType::Bool, true);
+    writeVar1->workVariable = &var;
+    writeVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
+    instructionList.addInstruction(writeVar1);
+
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList->workList = &list;
+    instructionList.addInstruction(clearList);
+
+    auto innerLoopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    instructionList.addInstruction(innerLoopStart);
+
+    // Read from variable and write to list in inner loop
+    auto readVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVarReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
+    readVar->functionReturnReg = readVarReg.get();
+    readVarReg->instruction = readVar;
+    readVar->workVariable = &var;
+    instructionList.addInstruction(readVar);
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, readVarReg.get() });
+    instructionList.addInstruction(appendList);
+
+    // Write different type to variable in inner loop (creates conflict)
+    auto writeVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value2(Compiler::StaticType::String, "conflict");
+    writeVar2->workVariable = &var;
+    writeVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
+    instructionList.addInstruction(writeVar2);
+
+    auto innerLoopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(innerLoopEnd);
+
+    auto outerLoopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    instructionList.addInstruction(outerLoopEnd);
+
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    instructionList.addInstruction(funcCall);
+
+    // Should return Unknown due to type conflicts in nested loops
+    ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Unknown);
+    ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Bool, false), Compiler::StaticType::Unknown);
+}

From bd0d45ea8ad21509d3fa887ba975f9da33c6d954 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Fri, 1 Aug 2025 15:57:43 +0200
Subject: [PATCH 46/79] LLVMTypeAnalyzer: Add pointer const qualifiers

---
 src/engine/internal/llvm/llvmtypeanalyzer.cpp | 105 ++++++++++--------
 src/engine/internal/llvm/llvmtypeanalyzer.h   |  75 +++++++------
 2 files changed, 99 insertions(+), 81 deletions(-)

diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
index b0d4a6c9..bdbe2098 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
@@ -10,37 +10,40 @@ static const std::unordered_set<LLVMInstruction::Type>
 
 static const std::unordered_set<LLVMInstruction::Type> LIST_WRITE_INSTRUCTIONS = { LLVMInstruction::Type::AppendToList, LLVMInstruction::Type::InsertToList, LLVMInstruction::Type::ListReplace };
 
-Compiler::StaticType LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType) const
+Compiler::StaticType LLVMTypeAnalyzer::variableType(const Variable *var, const LLVMInstruction *pos, Compiler::StaticType previousType) const
 {
     InstructionSet visitedInstructions;
-    std::unordered_map<List *, Compiler::StaticType> listTypes;
+    std::unordered_map<const List *, Compiler::StaticType> listTypes;
     return variableType(var, pos, previousType, listTypes, visitedInstructions);
 }
 
-Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType) const
+Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(const Variable *var, const LLVMInstruction *start, Compiler::StaticType previousType) const
 {
     InstructionSet visitedInstructions;
     return variableTypeAfterBranch(var, start, previousType, visitedInstructions);
 }
 
-Compiler::StaticType LLVMTypeAnalyzer::listType(List *list, LLVMInstruction *pos, Compiler::StaticType previousType, bool isEmpty) const
+Compiler::StaticType LLVMTypeAnalyzer::listType(const List *list, const LLVMInstruction *pos, Compiler::StaticType previousType, bool isEmpty) const
 {
     InstructionSet visitedInstructions;
-    std::unordered_map<List *, Compiler::StaticType> listTypes;
+    std::unordered_map<const List *, Compiler::StaticType> listTypes;
     return listType(list, pos, previousType, isEmpty, listTypes, visitedInstructions);
 }
 
-Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch(List *list, LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty) const
+Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch(const List *list, const LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty) const
 {
     bool write = false; // only used internally (the compiler doesn't need this)
     InstructionSet visitedInstructions;
-    std::unordered_map<List *, Compiler::StaticType> listTypes;
+    std::unordered_map<const List *, Compiler::StaticType> listTypes;
     return listTypeAfterBranch(list, start, previousType, isEmpty, nullptr, write, listTypes, visitedInstructions);
 }
 
-Compiler::StaticType
-LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType, std::unordered_map<List *, Compiler::StaticType> listTypes, InstructionSet &visitedInstructions)
-    const
+Compiler::StaticType LLVMTypeAnalyzer::variableType(
+    const Variable *var,
+    const LLVMInstruction *pos,
+    Compiler::StaticType previousType,
+    std::unordered_map<const List *, Compiler::StaticType> listTypes,
+    InstructionSet &visitedInstructions) const
 {
     if (!var || !pos)
         return Compiler::StaticType::Unknown;
@@ -63,11 +66,11 @@ LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstruction *pos, Compiler::St
     visitedInstructions.insert(pos);
 
     // Check the last write operation before the instruction
-    LLVMInstruction *ins = pos;
-    LLVMInstruction *write = nullptr;
-    std::pair<LLVMInstruction *, int> firstBranch = { nullptr, 0 };
-    std::pair<LLVMInstruction *, int> firstElseBranch = { nullptr, 0 };
-    LLVMInstruction *ourBranch = nullptr;
+    const LLVMInstruction *ins = pos;
+    const LLVMInstruction *write = nullptr;
+    std::pair<const LLVMInstruction *, int> firstBranch = { nullptr, 0 };
+    std::pair<const LLVMInstruction *, int> firstElseBranch = { nullptr, 0 };
+    const LLVMInstruction *ourBranch = nullptr;
     int level = 0;
 
     while (ins) {
@@ -126,32 +129,32 @@ LLVMTypeAnalyzer::variableType(Variable *var, LLVMInstruction *pos, Compiler::St
     return previousType;
 }
 
-Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const
+Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranch(const Variable *var, const LLVMInstruction *start, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const
 {
     if (!var || !start)
         return previousType;
 
-    LLVMInstruction *end = branchEnd(start);
+    const LLVMInstruction *end = branchEnd(start);
 
     if (!end)
         return Compiler::StaticType::Unknown;
 
     // Process the branch from end
     bool write = false; // only used internally (the compiler doesn't need this)
-    std::unordered_map<List *, Compiler::StaticType> listTypes;
+    std::unordered_map<const List *, Compiler::StaticType> listTypes;
     return variableTypeAfterBranchFromEnd(var, end, previousType, write, listTypes, visitedInstructions);
 }
 
 Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(
-    Variable *var,
-    LLVMInstruction *end,
+    const Variable *var,
+    const LLVMInstruction *end,
     Compiler::StaticType previousType,
     bool &write,
-    std::unordered_map<List *, Compiler::StaticType> listTypes,
+    std::unordered_map<const List *, Compiler::StaticType> listTypes,
     InstructionSet &visitedInstructions) const
 {
     // Find the last write instruction
-    LLVMInstruction *ins = end->previous;
+    const LLVMInstruction *ins = end->previous;
     bool typeMightReset = false;
 
     while (ins && !isLoopStart(ins) && !isIfStart(ins)) {
@@ -201,8 +204,13 @@ Compiler::StaticType LLVMTypeAnalyzer::variableTypeAfterBranchFromEnd(
     return previousType;
 }
 
-Compiler::StaticType LLVMTypeAnalyzer::
-    listType(List *list, LLVMInstruction *pos, Compiler::StaticType previousType, bool isEmpty, std::unordered_map<List *, Compiler::StaticType> listTypes, InstructionSet &visitedInstructions) const
+Compiler::StaticType LLVMTypeAnalyzer::listType(
+    const List *list,
+    const LLVMInstruction *pos,
+    Compiler::StaticType previousType,
+    bool isEmpty,
+    std::unordered_map<const List *, Compiler::StaticType> listTypes,
+    InstructionSet &visitedInstructions) const
 {
     if (!list || !pos)
         return Compiler::StaticType::Unknown;
@@ -223,10 +231,10 @@ Compiler::StaticType LLVMTypeAnalyzer::
     visitedInstructions.insert(pos);
     listTypes[list] = previousType;
 
-    LLVMInstruction *ins = pos;
-    LLVMInstruction *previous = nullptr;
-    std::pair<LLVMInstruction *, int> firstBranch = { nullptr, 0 };
-    std::pair<LLVMInstruction *, int> lastClear = { nullptr, 0 };
+    const LLVMInstruction *ins = pos;
+    const LLVMInstruction *previous = nullptr;
+    std::pair<const LLVMInstruction *, int> firstBranch = { nullptr, 0 };
+    std::pair<const LLVMInstruction *, int> lastClear = { nullptr, 0 };
     int level = 0;
 
     // Find a start instruction (list clear in the top level or the first instruction)
@@ -305,13 +313,13 @@ Compiler::StaticType LLVMTypeAnalyzer::
 }
 
 Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch(
-    List *list,
-    LLVMInstruction *start,
+    const List *list,
+    const LLVMInstruction *start,
     Compiler::StaticType previousType,
     bool isEmpty,
-    LLVMInstruction *query,
+    const LLVMInstruction *query,
     bool &write,
-    std::unordered_map<List *, Compiler::StaticType> listTypes,
+    std::unordered_map<const List *, Compiler::StaticType> listTypes,
     InstructionSet &visitedInstructions) const
 {
     write = false;
@@ -323,7 +331,7 @@ Compiler::StaticType LLVMTypeAnalyzer::listTypeAfterBranch(
 
     bool isLoop = isLoopStart(start);
     bool clearBeforeQueryPoint = false;
-    LLVMInstruction *ins = start->next;
+    const LLVMInstruction *ins = start->next;
 
     while (ins && !(isLoopEnd(ins) || isIfEnd(ins) || isElse(ins))) {
         if (isLoopStart(ins) || isIfStart(ins)) {
@@ -385,7 +393,7 @@ bool LLVMTypeAnalyzer::handleListWrite(Compiler::StaticType writeType, Compiler:
     return true;
 }
 
-LLVMInstruction *LLVMTypeAnalyzer::branchEnd(LLVMInstruction *start) const
+const LLVMInstruction *LLVMTypeAnalyzer::branchEnd(const LLVMInstruction *start) const
 {
     assert(start);
     assert(isLoopStart(start) || isIfStart(start) || isElse(start));
@@ -409,7 +417,7 @@ LLVMInstruction *LLVMTypeAnalyzer::branchEnd(LLVMInstruction *start) const
     return ins;
 }
 
-LLVMInstruction *LLVMTypeAnalyzer::branchStart(LLVMInstruction *end) const
+const LLVMInstruction *LLVMTypeAnalyzer::branchStart(const LLVMInstruction *end) const
 {
     assert(end);
     assert(isLoopEnd(end) || isIfEnd(end) || isElse(end));
@@ -434,52 +442,52 @@ LLVMInstruction *LLVMTypeAnalyzer::branchStart(LLVMInstruction *end) const
     return ins;
 }
 
-bool LLVMTypeAnalyzer::isLoopStart(LLVMInstruction *ins) const
+bool LLVMTypeAnalyzer::isLoopStart(const LLVMInstruction *ins) const
 {
     return (BEGIN_LOOP_INSTRUCTIONS.find(ins->type) != BEGIN_LOOP_INSTRUCTIONS.cend());
 }
 
-bool LLVMTypeAnalyzer::isLoopEnd(LLVMInstruction *ins) const
+bool LLVMTypeAnalyzer::isLoopEnd(const LLVMInstruction *ins) const
 {
     return (ins->type == LLVMInstruction::Type::EndLoop);
 }
 
-bool LLVMTypeAnalyzer::isIfStart(LLVMInstruction *ins) const
+bool LLVMTypeAnalyzer::isIfStart(const LLVMInstruction *ins) const
 {
     return (ins->type == LLVMInstruction::Type::BeginIf);
 }
 
-bool LLVMTypeAnalyzer::isElse(LLVMInstruction *ins) const
+bool LLVMTypeAnalyzer::isElse(const LLVMInstruction *ins) const
 {
     return (ins->type == LLVMInstruction::Type::BeginElse);
 }
 
-bool LLVMTypeAnalyzer::isIfEnd(LLVMInstruction *ins) const
+bool LLVMTypeAnalyzer::isIfEnd(const LLVMInstruction *ins) const
 {
     return (ins->type == LLVMInstruction::Type::EndIf);
 }
 
-bool LLVMTypeAnalyzer::isVariableRead(LLVMInstruction *ins) const
+bool LLVMTypeAnalyzer::isVariableRead(const LLVMInstruction *ins) const
 {
     return (ins->type == LLVMInstruction::Type::ReadVariable);
 }
 
-bool LLVMTypeAnalyzer::isVariableWrite(LLVMInstruction *ins, Variable *var) const
+bool LLVMTypeAnalyzer::isVariableWrite(const LLVMInstruction *ins, const Variable *var) const
 {
     return (ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == var);
 }
 
-bool LLVMTypeAnalyzer::isListRead(LLVMInstruction *ins) const
+bool LLVMTypeAnalyzer::isListRead(const LLVMInstruction *ins) const
 {
     return (ins->type == LLVMInstruction::Type::GetListItem);
 }
 
-bool LLVMTypeAnalyzer::isListWrite(LLVMInstruction *ins, List *list) const
+bool LLVMTypeAnalyzer::isListWrite(const LLVMInstruction *ins, const List *list) const
 {
     return (LIST_WRITE_INSTRUCTIONS.find(ins->type) != LIST_WRITE_INSTRUCTIONS.cend() && ins->workList == list);
 }
 
-bool LLVMTypeAnalyzer::isListClear(LLVMInstruction *ins, List *list) const
+bool LLVMTypeAnalyzer::isListClear(const LLVMInstruction *ins, const List *list) const
 {
     return (ins->type == LLVMInstruction::Type::ClearList && ins->workList == list);
 }
@@ -498,7 +506,7 @@ Compiler::StaticType LLVMTypeAnalyzer::optimizeRegisterType(LLVMRegister *reg) c
     return ret;
 }
 
-bool LLVMTypeAnalyzer::isWriteNoOp(LLVMInstruction *ins) const
+bool LLVMTypeAnalyzer::isWriteNoOp(const LLVMInstruction *ins) const
 {
     assert(ins);
     assert(!ins->args.empty());
@@ -515,7 +523,7 @@ bool LLVMTypeAnalyzer::isWriteNoOp(LLVMInstruction *ins) const
     return false;
 }
 
-Compiler::StaticType LLVMTypeAnalyzer::writeValueType(LLVMInstruction *ins, std::unordered_map<List *, Compiler::StaticType> listTypes, InstructionSet &visitedInstructions) const
+Compiler::StaticType LLVMTypeAnalyzer::writeValueType(const LLVMInstruction *ins, std::unordered_map<const List *, Compiler::StaticType> listTypes, InstructionSet &visitedInstructions) const
 {
     assert(ins);
     assert(!ins->args.empty());
@@ -550,7 +558,8 @@ bool LLVMTypeAnalyzer::typesMatch(Compiler::StaticType a, Compiler::StaticType b
     return (a == b) && (a != Compiler::StaticType::Unknown);
 }
 
-bool LLVMTypeAnalyzer::writeTypesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType, std::unordered_map<List *, Compiler::StaticType> listTypes, InstructionSet &visitedInstructions) const
+bool LLVMTypeAnalyzer::
+    writeTypesMatch(const LLVMInstruction *ins, Compiler::StaticType expectedType, std::unordered_map<const List *, Compiler::StaticType> listTypes, InstructionSet &visitedInstructions) const
 {
     return typesMatch(writeValueType(ins, listTypes, visitedInstructions), expectedType);
 }
diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.h b/src/engine/internal/llvm/llvmtypeanalyzer.h
index d5f965df..4244d2b8 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.h
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.h
@@ -12,65 +12,74 @@ struct LLVMRegister;
 class LLVMTypeAnalyzer
 {
     public:
-        Compiler::StaticType variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType) const;
-        Compiler::StaticType variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType) const;
+        Compiler::StaticType variableType(const Variable *var, const LLVMInstruction *pos, Compiler::StaticType previousType) const;
+        Compiler::StaticType variableTypeAfterBranch(const Variable *var, const LLVMInstruction *start, Compiler::StaticType previousType) const;
 
-        Compiler::StaticType listType(List *list, LLVMInstruction *pos, Compiler::StaticType previousType, bool isEmpty) const;
-        Compiler::StaticType listTypeAfterBranch(List *list, LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty) const;
+        Compiler::StaticType listType(const List *list, const LLVMInstruction *pos, Compiler::StaticType previousType, bool isEmpty) const;
+        Compiler::StaticType listTypeAfterBranch(const List *list, const LLVMInstruction *start, Compiler::StaticType previousType, bool isEmpty) const;
 
     private:
-        using InstructionSet = std::unordered_set<LLVMInstruction *>;
+        using InstructionSet = std::unordered_set<const LLVMInstruction *>;
 
-        Compiler::StaticType
-        variableType(Variable *var, LLVMInstruction *pos, Compiler::StaticType previousType, std::unordered_map<List *, Compiler::StaticType> listTypes, InstructionSet &visitedInstructions) const;
+        Compiler::StaticType variableType(
+            const Variable *var,
+            const LLVMInstruction *pos,
+            Compiler::StaticType previousType,
+            std::unordered_map<const List *, Compiler::StaticType> listTypes,
+            InstructionSet &visitedInstructions) const;
 
-        Compiler::StaticType variableTypeAfterBranch(Variable *var, LLVMInstruction *start, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const;
+        Compiler::StaticType variableTypeAfterBranch(const Variable *var, const LLVMInstruction *start, Compiler::StaticType previousType, InstructionSet &visitedInstructions) const;
 
         Compiler::StaticType variableTypeAfterBranchFromEnd(
-            Variable *var,
-            LLVMInstruction *end,
+            const Variable *var,
+            const LLVMInstruction *end,
             Compiler::StaticType previousType,
             bool &write,
-            std::unordered_map<List *, Compiler::StaticType> listTypes,
+            std::unordered_map<const List *, Compiler::StaticType> listTypes,
             InstructionSet &visitedInstructions) const;
 
-        Compiler::StaticType
-        listType(List *list, LLVMInstruction *pos, Compiler::StaticType previousType, bool isEmpty, std::unordered_map<List *, Compiler::StaticType> listTypes, InstructionSet &visitedInstructions)
-            const;
+        Compiler::StaticType listType(
+            const List *list,
+            const LLVMInstruction *pos,
+            Compiler::StaticType previousType,
+            bool isEmpty,
+            std::unordered_map<const List *, Compiler::StaticType> listTypes,
+            InstructionSet &visitedInstructions) const;
 
         Compiler::StaticType listTypeAfterBranch(
-            List *list,
-            LLVMInstruction *start,
+            const List *list,
+            const LLVMInstruction *start,
             Compiler::StaticType previousType,
             bool isEmpty,
-            LLVMInstruction *query,
+            const LLVMInstruction *query,
             bool &write,
-            std::unordered_map<List *, Compiler::StaticType> listTypes,
+            std::unordered_map<const List *, Compiler::StaticType> listTypes,
             InstructionSet &visitedInstructions) const;
 
         bool handleListWrite(Compiler::StaticType writeType, Compiler::StaticType &previousType, bool &isEmpty) const;
 
-        LLVMInstruction *branchEnd(LLVMInstruction *start) const;
-        LLVMInstruction *branchStart(LLVMInstruction *end) const;
+        const LLVMInstruction *branchEnd(const LLVMInstruction *start) const;
+        const LLVMInstruction *branchStart(const LLVMInstruction *end) const;
 
-        bool isLoopStart(LLVMInstruction *ins) const;
-        bool isLoopEnd(LLVMInstruction *ins) const;
-        bool isIfStart(LLVMInstruction *ins) const;
-        bool isElse(LLVMInstruction *ins) const;
-        bool isIfEnd(LLVMInstruction *ins) const;
+        bool isLoopStart(const LLVMInstruction *ins) const;
+        bool isLoopEnd(const LLVMInstruction *ins) const;
+        bool isIfStart(const LLVMInstruction *ins) const;
+        bool isElse(const LLVMInstruction *ins) const;
+        bool isIfEnd(const LLVMInstruction *ins) const;
 
-        bool isVariableRead(LLVMInstruction *ins) const;
-        bool isVariableWrite(LLVMInstruction *ins, Variable *var) const;
+        bool isVariableRead(const LLVMInstruction *ins) const;
+        bool isVariableWrite(const LLVMInstruction *ins, const Variable *var) const;
 
-        bool isListRead(LLVMInstruction *ins) const;
-        bool isListWrite(LLVMInstruction *ins, List *list) const;
-        bool isListClear(LLVMInstruction *ins, List *list) const;
+        bool isListRead(const LLVMInstruction *ins) const;
+        bool isListWrite(const LLVMInstruction *ins, const List *list) const;
+        bool isListClear(const LLVMInstruction *ins, const List *list) const;
 
         Compiler::StaticType optimizeRegisterType(LLVMRegister *reg) const;
-        bool isWriteNoOp(LLVMInstruction *ins) const;
-        Compiler::StaticType writeValueType(LLVMInstruction *ins, std::unordered_map<List *, Compiler::StaticType> listTypes, InstructionSet &visitedInstructions) const;
+        bool isWriteNoOp(const LLVMInstruction *ins) const;
+        Compiler::StaticType writeValueType(const LLVMInstruction *ins, std::unordered_map<const List *, Compiler::StaticType> listTypes, InstructionSet &visitedInstructions) const;
         bool typesMatch(Compiler::StaticType a, Compiler::StaticType b) const;
-        bool writeTypesMatch(LLVMInstruction *ins, Compiler::StaticType expectedType, std::unordered_map<List *, Compiler::StaticType> listTypes, InstructionSet &visitedInstructions) const;
+        bool
+        writeTypesMatch(const LLVMInstruction *ins, Compiler::StaticType expectedType, std::unordered_map<const List *, Compiler::StaticType> listTypes, InstructionSet &visitedInstructions) const;
 };
 
 } // namespace libscratchcpp

From 133814e2a5063ebb73eb0808b7c1c98eb04782fd Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Fri, 1 Aug 2025 16:14:30 +0200
Subject: [PATCH 47/79] LLVMTypeAnalyzer: Do not process query point in
 variableType()

---
 src/engine/internal/llvm/llvmtypeanalyzer.cpp |  2 +-
 test/llvm/type_analyzer/listtype_test.cpp     | 15 +++++++++++++++
 test/llvm/type_analyzer/variabletype_test.cpp | 15 +++++++++++++++
 3 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.cpp b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
index bdbe2098..3445c783 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.cpp
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.cpp
@@ -66,7 +66,7 @@ Compiler::StaticType LLVMTypeAnalyzer::variableType(
     visitedInstructions.insert(pos);
 
     // Check the last write operation before the instruction
-    const LLVMInstruction *ins = pos;
+    const LLVMInstruction *ins = pos->previous;
     const LLVMInstruction *write = nullptr;
     std::pair<const LLVMInstruction *, int> firstBranch = { nullptr, 0 };
     std::pair<const LLVMInstruction *, int> firstElseBranch = { nullptr, 0 };
diff --git a/test/llvm/type_analyzer/listtype_test.cpp b/test/llvm/type_analyzer/listtype_test.cpp
index e44cf825..54e6bc98 100644
--- a/test/llvm/type_analyzer/listtype_test.cpp
+++ b/test/llvm/type_analyzer/listtype_test.cpp
@@ -79,6 +79,21 @@ TEST(LLVMTypeAnalyzer_ListType, NoWriteOperationsUnknownType_Empty)
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Unknown, true), Compiler::StaticType::Unknown);
 }
 
+TEST(LLVMTypeAnalyzer_ListType, QueryPointIsWrite)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList instructionList;
+    List list("", "");
+
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 1.25);
+    appendList->workList = &list;
+    appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
+    instructionList.addInstruction(appendList);
+
+    ASSERT_EQ(analyzer.listType(&list, appendList.get(), Compiler::StaticType::String, false), Compiler::StaticType::String);
+}
+
 TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteSameTypeNumber_Before_NonEmpty)
 {
     LLVMTypeAnalyzer analyzer;
diff --git a/test/llvm/type_analyzer/variabletype_test.cpp b/test/llvm/type_analyzer/variabletype_test.cpp
index 1d167588..ea7090e8 100644
--- a/test/llvm/type_analyzer/variabletype_test.cpp
+++ b/test/llvm/type_analyzer/variabletype_test.cpp
@@ -55,6 +55,21 @@ TEST(LLVMTypeAnalyzer_VariableType, NoWriteOperationsUnknownType)
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown);
 }
 
+TEST(LLVMTypeAnalyzer_VariableType, QueryPointIsWrite)
+{
+    LLVMTypeAnalyzer analyzer;
+    LLVMInstructionList list;
+    Variable var("", "");
+
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    LLVMConstantRegister value(Compiler::StaticType::Number, 1.25);
+    setVar->workVariable = &var;
+    setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
+    list.addInstruction(setVar);
+
+    ASSERT_EQ(analyzer.variableType(&var, setVar.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown);
+}
+
 TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeNumber_Before)
 {
     LLVMTypeAnalyzer analyzer;

From 0521d0452b006d861faa2b92dc14ba3f15870dc3 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Fri, 1 Aug 2025 16:54:43 +0200
Subject: [PATCH 48/79] Use LLVMTypeAnalyzer for static type analysis

---
 src/engine/internal/llvm/llvmcodebuilder.cpp |  359 +---
 src/engine/internal/llvm/llvmcodebuilder.h   |    9 +-
 src/engine/internal/llvm/llvmlistptr.h       |    1 -
 src/engine/internal/llvm/llvmvariableptr.h   |    1 -
 test/llvm/llvmcodebuilder_test.cpp           | 1758 ++----------------
 5 files changed, 215 insertions(+), 1913 deletions(-)

diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp
index b61a477b..12043512 100644
--- a/src/engine/internal/llvm/llvmcodebuilder.cpp
+++ b/src/engine/internal/llvm/llvmcodebuilder.cpp
@@ -116,7 +116,11 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
         // All variables are currently created on the stack and synced later (seems to be faster)
         // NOTE: Strings are NOT copied, only the pointer is copied
-        varPtr.stackPtr = m_builder.CreateAlloca(m_valueDataType);
+        // TODO: Restore this feature
+        // varPtr.stackPtr = m_builder.CreateAlloca(m_valueDataType);
+        varPtr.stackPtr = varPtr.heapPtr;
+        varPtr.onStack = false;
+        continue;
 
         // If there are no write operations outside loops, initialize the stack variable now
         Variable *variable = var;
@@ -147,8 +151,6 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
     assert(m_loopScope == -1);
     m_loopScope = -1;
-    m_scopeVariables.clear();
-    m_scopeLists.clear();
     pushScopeLevel();
 
     // Execute recorded steps
@@ -738,14 +740,18 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 assert(step.args.size() == 1);
                 assert(m_variablePtrs.find(step.workVariable) != m_variablePtrs.cend());
                 const auto &arg = step.args[0];
-                Compiler::StaticType type = optimizeRegisterType(arg.second);
+                Compiler::StaticType argType = optimizeRegisterType(arg.second);
                 LLVMVariablePtr &varPtr = m_variablePtrs[step.workVariable];
-                varPtr.changed = true;
+                varPtr.changed = true; // TODO: Handle loops and if statements
 
-                const bool safe = isVarOrListTypeSafe(insPtr, varPtr.type);
+                Compiler::StaticType varType = Compiler::StaticType::Unknown;
+
+                if (m_warp)
+                    varType = m_typeAnalyzer.variableType(step.workVariable, &step, Compiler::StaticType::Unknown);
 
                 // Initialize stack variable on first assignment
-                if (!varPtr.onStack) {
+                // TODO: Use stack in the top level (outside loops and if statements)
+                /*if (!varPtr.onStack) {
                     varPtr.onStack = true;
                     varPtr.type = type; // don't care about unknown type on first assignment
 
@@ -762,26 +768,22 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
                     llvm::Value *typeField = m_builder.CreateStructGEP(m_valueDataType, varPtr.stackPtr, 1);
                     m_builder.CreateStore(m_builder.getInt32(static_cast<uint32_t>(mappedType)), typeField);
-                }
-
-                if (!safe)
-                    varPtr.type = Compiler::StaticType::Unknown;
+                }*/
 
-                createValueStore(arg.second, varPtr.stackPtr, type, varPtr.type);
-                varPtr.type = type;
-                m_scopeVariables.back()[&varPtr] = varPtr.type;
+                createValueStore(arg.second, varPtr.stackPtr, argType, varType);
                 break;
             }
 
             case LLVMInstruction::Type::ReadVariable: {
                 assert(step.args.size() == 0);
                 LLVMVariablePtr &varPtr = m_variablePtrs[step.workVariable];
+                Compiler::StaticType type = Compiler::StaticType::Unknown;
 
-                if (!isVarOrListTypeSafe(insPtr, varPtr.type))
-                    varPtr.type = Compiler::StaticType::Unknown;
+                if (m_warp)
+                    type = m_typeAnalyzer.variableType(step.workVariable, &step, Compiler::StaticType::Unknown);
 
                 step.functionReturnReg->value = varPtr.onStack && !(step.loopCondition && !m_warp) ? varPtr.stackPtr : varPtr.heapPtr;
-                step.functionReturnReg->setType(varPtr.type);
+                step.functionReturnReg->setType(type);
                 break;
             }
 
@@ -795,8 +797,6 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Value *dataPtrDirty = m_builder.CreateLoad(m_builder.getInt1Ty(), listPtr.dataPtrDirty);
                 llvm::Value *allocatedSize = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.allocatedSizePtr);
                 m_builder.CreateStore(m_builder.CreateOr(dataPtrDirty, m_builder.CreateICmpNE(allocatedSize, oldAllocatedSize)), listPtr.dataPtrDirty);
-
-                m_scopeLists.back().erase(&listPtr);
                 break;
             }
 
@@ -805,9 +805,6 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 const auto &arg = step.args[0];
                 LLVMListPtr &listPtr = m_listPtrs[step.workList];
 
-                if (!isVarOrListTypeSafe(insPtr, listPtr.type))
-                    listPtr.type = Compiler::StaticType::Unknown;
-
                 // Range check
                 llvm::Value *min = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0));
                 llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.sizePtr);
@@ -835,18 +832,10 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 Compiler::StaticType type = optimizeRegisterType(arg.second);
                 LLVMListPtr &listPtr = m_listPtrs[step.workList];
 
-                auto &typeMap = m_scopeLists.back();
-
-                if (typeMap.find(&listPtr) == typeMap.cend()) {
-                    listPtr.type = type;
-                    typeMap[&listPtr] = listPtr.type;
-                } else if (listPtr.type != type) {
-                    listPtr.type = Compiler::StaticType::Unknown;
-                    typeMap[&listPtr] = listPtr.type;
-                }
+                Compiler::StaticType listType = Compiler::StaticType::Unknown;
 
-                if (!isVarOrListTypeSafe(insPtr, listPtr.type))
-                    listPtr.type = Compiler::StaticType::Unknown;
+                if (m_warp)
+                    listType = m_typeAnalyzer.listType(step.workList, &step, Compiler::StaticType::Unknown, false);
 
                 // Check if enough space is allocated
                 llvm::Value *allocatedSize = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.allocatedSizePtr);
@@ -860,14 +849,14 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 // If there's enough space, use the allocated memory
                 m_builder.SetInsertPoint(ifBlock);
                 llvm::Value *itemPtr = getListItem(listPtr, size);
-                createReusedValueStore(arg.second, itemPtr, type, listPtr.type);
+                createReusedValueStore(arg.second, itemPtr, type, listType);
                 m_builder.CreateStore(m_builder.CreateAdd(size, m_builder.getInt64(1)), listPtr.sizePtr);
                 m_builder.CreateBr(nextBlock);
 
                 // Otherwise call appendEmpty()
                 m_builder.SetInsertPoint(elseBlock);
                 itemPtr = m_builder.CreateCall(resolve_list_append_empty(), listPtr.ptr);
-                createReusedValueStore(arg.second, itemPtr, type, listPtr.type);
+                createReusedValueStore(arg.second, itemPtr, type, listType);
                 m_builder.CreateStore(m_builder.getInt1(true), listPtr.dataPtrDirty);
                 m_builder.CreateBr(nextBlock);
 
@@ -883,18 +872,10 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 Compiler::StaticType type = optimizeRegisterType(valueArg.second);
                 LLVMListPtr &listPtr = m_listPtrs[step.workList];
 
-                auto &typeMap = m_scopeLists.back();
+                Compiler::StaticType listType = Compiler::StaticType::Unknown;
 
-                if (typeMap.find(&listPtr) == typeMap.cend()) {
-                    listPtr.type = type;
-                    typeMap[&listPtr] = listPtr.type;
-                } else if (listPtr.type != type) {
-                    listPtr.type = Compiler::StaticType::Unknown;
-                    typeMap[&listPtr] = listPtr.type;
-                }
-
-                if (!isVarOrListTypeSafe(insPtr, listPtr.type))
-                    listPtr.type = Compiler::StaticType::Unknown;
+                if (m_warp)
+                    listType = m_typeAnalyzer.listType(step.workList, &step, Compiler::StaticType::Unknown, false);
 
                 llvm::Value *oldAllocatedSize = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.allocatedSizePtr);
 
@@ -912,7 +893,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 m_builder.SetInsertPoint(insertBlock);
                 index = m_builder.CreateFPToUI(index, m_builder.getInt64Ty());
                 llvm::Value *itemPtr = m_builder.CreateCall(resolve_list_insert_empty(), { listPtr.ptr, index });
-                createReusedValueStore(valueArg.second, itemPtr, type, listPtr.type);
+                createReusedValueStore(valueArg.second, itemPtr, type, listType);
 
                 // Check if the allocated size changed
                 llvm::Value *dataPtrDirty = m_builder.CreateLoad(m_builder.getInt1Ty(), listPtr.dataPtrDirty);
@@ -932,8 +913,10 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 Compiler::StaticType type = optimizeRegisterType(valueArg.second);
                 LLVMListPtr &listPtr = m_listPtrs[step.workList];
 
-                if (!isVarOrListTypeSafe(insPtr, listPtr.type))
-                    listPtr.type = Compiler::StaticType::Unknown;
+                Compiler::StaticType listType = Compiler::StaticType::Unknown;
+
+                if (m_warp)
+                    listType = m_typeAnalyzer.listType(step.workList, &step, Compiler::StaticType::Unknown, false);
 
                 // Range check
                 llvm::Value *min = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0));
@@ -949,19 +932,9 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 m_builder.SetInsertPoint(replaceBlock);
                 index = m_builder.CreateFPToUI(index, m_builder.getInt64Ty());
                 llvm::Value *itemPtr = getListItem(listPtr, index);
-                createValueStore(valueArg.second, itemPtr, type, listPtr.type);
+                createValueStore(valueArg.second, itemPtr, type, listType);
                 m_builder.CreateBr(nextBlock);
 
-                auto &typeMap = m_scopeLists.back();
-
-                if (typeMap.find(&listPtr) == typeMap.cend()) {
-                    listPtr.type = type;
-                    typeMap[&listPtr] = listPtr.type;
-                } else if (listPtr.type != type) {
-                    listPtr.type = Compiler::StaticType::Unknown;
-                    typeMap[&listPtr] = listPtr.type;
-                }
-
                 m_builder.SetInsertPoint(nextBlock);
                 break;
             }
@@ -980,8 +953,10 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 const auto &arg = step.args[0];
                 LLVMListPtr &listPtr = m_listPtrs[step.workList];
 
-                if (!isVarOrListTypeSafe(insPtr, listPtr.type))
-                    listPtr.type = Compiler::StaticType::Unknown;
+                Compiler::StaticType listType = Compiler::StaticType::Unknown;
+
+                if (m_warp)
+                    listType = m_typeAnalyzer.listType(step.workList, &step, Compiler::StaticType::Unknown, false);
 
                 llvm::Value *min = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0));
                 llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.sizePtr);
@@ -989,12 +964,12 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Value *index = castValue(arg.second, arg.first);
                 llvm::Value *inRange = m_builder.CreateAnd(m_builder.CreateFCmpOGE(index, min), m_builder.CreateFCmpOLT(index, size));
 
-                LLVMConstantRegister nullReg(listPtr.type == Compiler::StaticType::Unknown ? Compiler::StaticType::Number : listPtr.type, Value());
+                LLVMConstantRegister nullReg(listType == Compiler::StaticType::Unknown ? Compiler::StaticType::Number : listType, Value());
                 llvm::Value *null = createValue(static_cast<LLVMRegister *>(&nullReg));
 
                 index = m_builder.CreateFPToUI(index, m_builder.getInt64Ty());
                 step.functionReturnReg->value = m_builder.CreateSelect(inRange, getListItem(listPtr, index), null);
-                step.functionReturnReg->setType(listPtr.type);
+                step.functionReturnReg->setType(listType);
                 break;
             }
 
@@ -1011,10 +986,12 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 const auto &arg = step.args[0];
                 LLVMListPtr &listPtr = m_listPtrs[step.workList];
 
-                if (!isVarOrListTypeSafe(insPtr, listPtr.type))
-                    listPtr.type = Compiler::StaticType::Unknown;
+                Compiler::StaticType listType = Compiler::StaticType::Unknown;
 
-                step.functionReturnReg->value = m_builder.CreateSIToFP(getListItemIndex(listPtr, arg.second), m_builder.getDoubleTy());
+                if (m_warp)
+                    listType = m_typeAnalyzer.listType(step.workList, &step, Compiler::StaticType::Unknown, false);
+
+                step.functionReturnReg->value = m_builder.CreateSIToFP(getListItemIndex(listPtr, listType, arg.second), m_builder.getDoubleTy());
                 break;
             }
 
@@ -1023,10 +1000,12 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 const auto &arg = step.args[0];
                 LLVMListPtr &listPtr = m_listPtrs[step.workList];
 
-                if (!isVarOrListTypeSafe(insPtr, listPtr.type))
-                    listPtr.type = Compiler::StaticType::Unknown;
+                Compiler::StaticType listType = Compiler::StaticType::Unknown;
 
-                llvm::Value *index = getListItemIndex(listPtr, arg.second);
+                if (m_warp)
+                    listType = m_typeAnalyzer.listType(step.workList, &step, Compiler::StaticType::Unknown, false);
+
+                llvm::Value *index = getListItemIndex(listPtr, listType, arg.second);
                 step.functionReturnReg->value = m_builder.CreateICmpSGT(index, llvm::ConstantInt::get(m_builder.getInt64Ty(), -1, true));
                 break;
             }
@@ -1058,15 +1037,6 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 assert(!ifStatements.empty());
                 LLVMIfStatement &statement = ifStatements.back();
 
-                // Restore types from parent scope
-                std::unordered_map<LLVMVariablePtr *, Compiler::StaticType> parentScopeVariables = m_scopeVariables[m_scopeVariables.size() - 2]; // no reference!
-                popScopeLevel();
-
-                for (auto &[ptr, type] : parentScopeVariables)
-                    ptr->type = type;
-
-                pushScopeLevel();
-
                 // Jump to the branch after the if statement
                 assert(!statement.afterIf);
                 statement.afterIf = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
@@ -1985,41 +1955,11 @@ void LLVMCodeBuilder::createListMap()
 
 void LLVMCodeBuilder::pushScopeLevel()
 {
-    m_scopeVariables.push_back({});
-
-    if (m_scopeLists.empty()) {
-        std::unordered_map<LLVMListPtr *, Compiler::StaticType> listTypes;
-
-        for (auto &[list, listPtr] : m_listPtrs)
-            listTypes[&listPtr] = Compiler::StaticType::Unknown;
-
-        m_scopeLists.push_back(listTypes);
-    } else
-        m_scopeLists.push_back(m_scopeLists.back());
-
     m_stringHeap.push_back({});
 }
 
 void LLVMCodeBuilder::popScopeLevel()
 {
-    for (size_t i = 0; i < m_scopeVariables.size() - 1; i++) {
-        for (auto &[ptr, type] : m_scopeVariables[i]) {
-            if (ptr->type != type)
-                ptr->type = Compiler::StaticType::Unknown;
-        }
-    }
-
-    m_scopeVariables.pop_back();
-
-    for (size_t i = 0; i < m_scopeLists.size() - 1; i++) {
-        for (auto &[ptr, type] : m_scopeLists[i]) {
-            if (ptr->type != type)
-                ptr->type = Compiler::StaticType::Unknown;
-        }
-    }
-
-    m_scopeLists.pop_back();
-
     freeScopeHeap();
     m_stringHeap.pop_back();
 }
@@ -2485,20 +2425,14 @@ void LLVMCodeBuilder::reloadVariables(llvm::Value *targetVariables)
     for (auto &[var, varPtr] : m_variablePtrs) {
         varPtr.onStack = false;
         varPtr.changed = false;
-        varPtr.type = Compiler::StaticType::Unknown;
     }
 }
 
 void LLVMCodeBuilder::reloadLists()
 {
-    // Reset list data dirty and list types
-    auto &typeMap = m_scopeLists.back();
-
-    for (auto &[list, listPtr] : m_listPtrs) {
+    // Reset list data dirty
+    for (auto &[list, listPtr] : m_listPtrs)
         m_builder.CreateStore(m_builder.getInt1(true), listPtr.dataPtrDirty);
-        listPtr.type = Compiler::StaticType::Unknown;
-        typeMap[&listPtr] = listPtr.type;
-    }
 }
 
 void LLVMCodeBuilder::updateListDataPtr(const LLVMListPtr &listPtr)
@@ -2511,193 +2445,6 @@ void LLVMCodeBuilder::updateListDataPtr(const LLVMListPtr &listPtr)
     m_builder.CreateStore(m_builder.getInt1(false), listPtr.dataPtrDirty);
 }
 
-bool LLVMCodeBuilder::isVarOrListTypeSafe(LLVMInstruction *ins, Compiler::StaticType expectedType) const
-{
-    std::unordered_set<LLVMInstruction *> processed;
-    int counter = 0;
-    return isVarOrListTypeSafe(ins, expectedType, processed, counter);
-}
-
-bool LLVMCodeBuilder::isVarOrListTypeSafe(LLVMInstruction *ins, Compiler::StaticType expectedType, std::unordered_set<LLVMInstruction *> &log, int &c) const
-{
-    /*
-     * The main part of the loop type analyzer.
-     *
-     * This is a recursive function which is called when variable
-     * or list instruction is created. It checks the last write to
-     * the variable or list in one of the loop scopes.
-     *
-     * If the last write operation writes a value with a different
-     * type, it will return false, otherwise true.
-     *
-     * If the last written value is from a variable or list, this
-     * function is called for it to check its type safety (that's
-     * why it is recursive).
-     *
-     * If the variable or list had a write operation before (in
-     * the same, parent or child loop scope), it is checked
-     * recursively.
-     */
-
-    if (!ins)
-        return false;
-
-    /*
-     * If we are processing something that has been already
-     * processed, it means there's a case like this:
-     * x = x
-     *
-     * or this:
-     * x = y
-     * ...
-     * y = x
-     *
-     * Increment counter to ignore last n write operations.
-     */
-    if (log.find(ins) != log.cend())
-        c++;
-    else
-        log.insert(ins);
-
-    assert(m_instructions.containsInstruction(ins));
-    const LLVMVariablePtr *varPtr = ins->workVariable ? &m_variablePtrs.at(ins->workVariable) : nullptr;
-    const LLVMListPtr *listPtr = ins->workList ? &m_listPtrs.at(ins->workList) : nullptr;
-    assert((varPtr || listPtr) && !(varPtr && listPtr));
-    auto scope = ins->loopScope;
-
-    // If we aren't in a loop, we're safe
-    if (!scope)
-        return true;
-
-    // If the loop scope contains a suspend and this is a non-warp script, the type may change between suspend and resume
-    if (scope->containsYield && !m_warp)
-        return false;
-
-    LLVMInstruction *write = nullptr;
-    const auto &instructions = varPtr ? m_variableInstructions : m_listInstructions;
-
-    // Find this instruction
-    auto it = std::find(instructions.begin(), instructions.end(), ins);
-    assert(it != instructions.end());
-
-    // Find previous write instruction in this, parent or child loop scope
-    size_t index = it - instructions.begin();
-
-    if (varPtr && index > 0) { // this is only needed for variables
-        bool found = false;
-
-        do {
-            index--;
-            write = instructions[index];
-            const bool isWrite = (VAR_LIST_READ_INSTRUCTIONS.find(write->type) == VAR_LIST_READ_INSTRUCTIONS.cend());
-            found = (write->loopScope && isWrite && write->workVariable == ins->workVariable);
-        } while (index > 0 && !found);
-
-        if (found) {
-            // Check if the write operation is in this or child scope
-            auto parentScope = write->loopScope;
-
-            while (parentScope && parentScope != scope)
-                parentScope = parentScope->parentScope;
-
-            if (!parentScope) {
-                // Check if the write operation is in any of the parent scopes
-                parentScope = scope;
-
-                do {
-                    parentScope = parentScope->parentScope;
-                } while (parentScope && parentScope != write->loopScope);
-            }
-
-            // If there was a write operation before this instruction (in this, parent or child scope), check it
-            if (parentScope) {
-                if (parentScope == scope)
-                    return isVarOrListWriteResultTypeSafe(write, expectedType, true, log, c);
-                else
-                    return isVarOrListTypeSafe(write, expectedType, log, c);
-            }
-        }
-    }
-
-    const auto &loopWrites = varPtr ? varPtr->loopVariableWrites : listPtr->loopListWrites;
-
-    // Find root loop scope
-    auto checkScope = scope;
-
-    while (checkScope->parentScope) {
-        checkScope = checkScope->parentScope;
-    }
-
-    // Get all write operations in all loop scopes (from the root loop scope)
-    std::vector<LLVMInstruction *> lastWrites;
-
-    while (checkScope) {
-        auto it = loopWrites.find(checkScope);
-
-        if (it != loopWrites.cend()) {
-            assert(!it->second.empty());
-            const auto &writes = it->second;
-
-            for (auto w : writes)
-                lastWrites.push_back(w);
-        }
-
-        if (checkScope->childScopes.empty())
-            checkScope = nullptr;
-        else
-            checkScope = checkScope->childScopes.back();
-    }
-
-    // If there aren't any write operations or all of them are ignored, we're safe
-    if (c >= lastWrites.size())
-        return true;
-
-    if (varPtr)
-        write = lastWrites[lastWrites.size() - c - 1]; // Ignore last c writes
-    else {
-        // If this is a list instruction, check last write operations except current
-        for (long i = lastWrites.size() - c - 1; i >= 0; i--) { // Ignore last c writes
-            if (lastWrites[i] == ins)
-                continue;
-
-            if (!isVarOrListWriteResultTypeSafe(lastWrites[i], expectedType, false, log, c))
-                return false;
-        }
-    }
-
-    bool safe = true;
-
-    if (VAR_LIST_READ_INSTRUCTIONS.find(ins->type) == VAR_LIST_READ_INSTRUCTIONS.cend()) // write
-        safe = isVarOrListWriteResultTypeSafe(ins, expectedType, false, log, c);
-
-    if (safe)
-        return write ? isVarOrListWriteResultTypeSafe(write, expectedType, false, log, c) : true;
-    else
-        return false;
-}
-
-bool LLVMCodeBuilder::isVarOrListWriteResultTypeSafe(LLVMInstruction *ins, Compiler::StaticType expectedType, bool ignoreSavedType, std::unordered_set<LLVMInstruction *> &log, int &c) const
-{
-    const LLVMVariablePtr *varPtr = ins->workVariable ? &m_variablePtrs.at(ins->workVariable) : nullptr;
-    const LLVMListPtr *listPtr = ins->workList ? &m_listPtrs.at(ins->workList) : nullptr;
-    assert((varPtr || listPtr) && !(varPtr && listPtr));
-
-    // If the write operation writes the value of another variable, recursively check its type safety
-    const auto arg = ins->args.back().second; // value is always the last argument
-    auto argIns = arg->instruction;
-
-    if (argIns && (argIns->type == LLVMInstruction::Type::ReadVariable || argIns->type == LLVMInstruction::Type::GetListItem))
-        return isVarOrListTypeSafe(argIns.get(), expectedType, log, c);
-
-    // Check written type
-    const bool typeMatches = (optimizeRegisterType(arg) == expectedType);
-
-    if (varPtr)
-        return typeMatches && (varPtr->type == expectedType || ignoreSavedType);
-    else
-        return typeMatches && (listPtr->type == expectedType || ignoreSavedType);
-}
-
 LLVMRegister *LLVMCodeBuilder::createOp(LLVMInstruction::Type type, Compiler::StaticType retType, Compiler::StaticType argType, const Compiler::Args &args)
 {
     return createOp({ type, currentLoopScope(), m_loopCondition }, retType, argType, args);
@@ -2854,7 +2601,7 @@ llvm::Value *LLVMCodeBuilder::getListItem(const LLVMListPtr &listPtr, llvm::Valu
     return m_builder.CreateGEP(m_valueDataType, m_builder.CreateLoad(m_valueDataType->getPointerTo(), listPtr.dataPtr), index);
 }
 
-llvm::Value *LLVMCodeBuilder::getListItemIndex(const LLVMListPtr &listPtr, LLVMRegister *item)
+llvm::Value *LLVMCodeBuilder::getListItemIndex(const LLVMListPtr &listPtr, Compiler::StaticType listType, LLVMRegister *item)
 {
     llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.sizePtr);
     llvm::BasicBlock *condBlock = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
@@ -2876,7 +2623,7 @@ llvm::Value *LLVMCodeBuilder::getListItemIndex(const LLVMListPtr &listPtr, LLVMR
 
     // if (list[index] == item)
     m_builder.SetInsertPoint(bodyBlock);
-    LLVMRegister currentItem(listPtr.type);
+    LLVMRegister currentItem(listType);
     currentItem.isRawValue = false;
     currentItem.value = getListItem(listPtr, m_builder.CreateLoad(m_builder.getInt64Ty(), index));
     llvm::Value *cmp = createComparison(&currentItem, item, Comparison::EQ);
diff --git a/src/engine/internal/llvm/llvmcodebuilder.h b/src/engine/internal/llvm/llvmcodebuilder.h
index a3b71b2e..2ddd8e98 100644
--- a/src/engine/internal/llvm/llvmcodebuilder.h
+++ b/src/engine/internal/llvm/llvmcodebuilder.h
@@ -15,6 +15,7 @@
 #include "llvmcoroutine.h"
 #include "llvmvariableptr.h"
 #include "llvmlistptr.h"
+#include "llvmtypeanalyzer.h"
 
 namespace libscratchcpp
 {
@@ -154,9 +155,6 @@ class LLVMCodeBuilder : public ICodeBuilder
         void reloadVariables(llvm::Value *targetVariables);
         void reloadLists();
         void updateListDataPtr(const LLVMListPtr &listPtr);
-        bool isVarOrListTypeSafe(LLVMInstruction *ins, Compiler::StaticType expectedType) const;
-        bool isVarOrListTypeSafe(LLVMInstruction *ins, Compiler::StaticType expectedType, std::unordered_set<LLVMInstruction *> &log, int &c) const;
-        bool isVarOrListWriteResultTypeSafe(LLVMInstruction *ins, Compiler::StaticType expectedType, bool ignoreSavedType, std::unordered_set<LLVMInstruction *> &log, int &c) const;
 
         LLVMRegister *createOp(LLVMInstruction::Type type, Compiler::StaticType retType, Compiler::StaticType argType, const Compiler::Args &args);
         LLVMRegister *createOp(LLVMInstruction::Type type, Compiler::StaticType retType, const Compiler::ArgTypes &argTypes = {}, const Compiler::Args &args = {});
@@ -169,7 +167,7 @@ class LLVMCodeBuilder : public ICodeBuilder
         void createValueCopy(llvm::Value *source, llvm::Value *target);
         void copyStructField(llvm::Value *source, llvm::Value *target, int index, llvm::StructType *structType, llvm::Type *fieldType);
         llvm::Value *getListItem(const LLVMListPtr &listPtr, llvm::Value *index);
-        llvm::Value *getListItemIndex(const LLVMListPtr &listPtr, LLVMRegister *item);
+        llvm::Value *getListItemIndex(const LLVMListPtr &listPtr, Compiler::StaticType listType, LLVMRegister *item);
         llvm::Value *createValue(LLVMRegister *reg);
         llvm::Value *createNewValue(LLVMRegister *reg);
         llvm::Value *createComparison(LLVMRegister *arg1, LLVMRegister *arg2, Comparison type);
@@ -219,17 +217,16 @@ class LLVMCodeBuilder : public ICodeBuilder
 
         std::unordered_map<Variable *, size_t> m_targetVariableMap;
         std::unordered_map<Variable *, LLVMVariablePtr> m_variablePtrs;
-        std::vector<std::unordered_map<LLVMVariablePtr *, Compiler::StaticType>> m_scopeVariables;
 
         std::unordered_map<List *, size_t> m_targetListMap;
         std::unordered_map<List *, LLVMListPtr> m_listPtrs;
-        std::vector<std::unordered_map<LLVMListPtr *, Compiler::StaticType>> m_scopeLists;
 
         LLVMCompilerContext *m_ctx;
         llvm::LLVMContext &m_llvmCtx;
         llvm::Module *m_module = nullptr;
         llvm::IRBuilder<> m_builder;
         llvm::Function *m_function = nullptr;
+        LLVMTypeAnalyzer m_typeAnalyzer;
 
         llvm::StructType *m_valueDataType = nullptr;
         llvm::StructType *m_stringPtrType = nullptr;
diff --git a/src/engine/internal/llvm/llvmlistptr.h b/src/engine/internal/llvm/llvmlistptr.h
index 2dd75869..52e4aff5 100644
--- a/src/engine/internal/llvm/llvmlistptr.h
+++ b/src/engine/internal/llvm/llvmlistptr.h
@@ -25,7 +25,6 @@ struct LLVMListPtr
         llvm::Value *sizePtr = nullptr;
         llvm::Value *allocatedSizePtr = nullptr;
         llvm::Value *dataPtrDirty = nullptr;
-        Compiler::StaticType type = Compiler::StaticType::Unknown;
 
         // Used in build phase to check the type safety of lists in loops
         std::unordered_map<LLVMLoopScope *, std::vector<LLVMInstruction *>> loopListWrites; // loop scope, write instructions
diff --git a/src/engine/internal/llvm/llvmvariableptr.h b/src/engine/internal/llvm/llvmvariableptr.h
index 9907a5aa..1627da6f 100644
--- a/src/engine/internal/llvm/llvmvariableptr.h
+++ b/src/engine/internal/llvm/llvmvariableptr.h
@@ -22,7 +22,6 @@ struct LLVMVariablePtr
 {
         llvm::Value *stackPtr = nullptr;
         llvm::Value *heapPtr = nullptr;
-        Compiler::StaticType type = Compiler::StaticType::Unknown;
         bool onStack = false;
         bool changed = false;
 
diff --git a/test/llvm/llvmcodebuilder_test.cpp b/test/llvm/llvmcodebuilder_test.cpp
index f32ad832..fcbed7b9 100644
--- a/test/llvm/llvmcodebuilder_test.cpp
+++ b/test/llvm/llvmcodebuilder_test.cpp
@@ -4222,8 +4222,9 @@ TEST_F(LLVMCodeBuilderTest, LoopVariables)
     ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
 }
 
-TEST_F(LLVMCodeBuilderTest, VariableLoopTypeAnalysis1)
+TEST_F(LLVMCodeBuilderTest, VariableLoopTypeAnalysis)
 {
+    // This just makes sure the type analyzer is used correctly
     Stage stage;
     Sprite sprite;
     sprite.setEngine(&m_engine);
@@ -4266,153 +4267,192 @@ TEST_F(LLVMCodeBuilderTest, VariableLoopTypeAnalysis1)
     ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
 }
 
-TEST_F(LLVMCodeBuilderTest, VariableLoopTypeAnalysis2)
+TEST_F(LLVMCodeBuilderTest, LoopLists)
 {
     Stage stage;
     Sprite sprite;
     sprite.setEngine(&m_engine);
     EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
 
-    auto globalVar = std::make_shared<Variable>("", "");
-    stage.addVariable(globalVar);
-
-    auto localVar = std::make_shared<Variable>("", "");
-    sprite.addVariable(localVar);
+    auto globalList1 = std::make_shared<List>("", "");
+    stage.addList(globalList1);
 
-    createBuilder(&sprite, true);
+    auto globalList2 = std::make_shared<List>("", "");
+    stage.addList(globalList2);
 
-    CompilerValue *v = m_builder->addConstValue(5.25);
-    m_builder->createVariableWrite(localVar.get(), v);
+    auto localList = std::make_shared<List>("", "");
+    sprite.addList(localList);
 
-    v = m_builder->addConstValue(2);
-    m_builder->beginRepeatLoop(v);
-    {
-        // Type is known here because a number is assigned later
-        v = m_builder->addVariableValue(localVar.get());
-        m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
+    auto counter1 = std::make_shared<Variable>("", "");
+    auto counter2 = std::make_shared<Variable>("", "");
+    sprite.addVariable(counter1);
+    sprite.addVariable(counter2);
 
-        v = m_builder->addConstValue(12.5);
-        m_builder->createVariableWrite(localVar.get(), v);
-    }
-    m_builder->endLoop();
+    createBuilder(&sprite, true);
 
-    std::string expected =
-        "5.25\n"
-        "12.5\n";
+    auto resetLists = [this, globalList1, globalList2, localList]() {
+        m_builder->createListClear(globalList1.get());
+        m_builder->createListClear(globalList2.get());
+        m_builder->createListClear(localList.get());
 
-    auto code = m_builder->finalize();
-    Script script(&sprite, nullptr, nullptr);
-    script.setCode(code);
-    Thread thread(&sprite, nullptr, &script);
-    auto ctx = code->createExecutionContext(&thread);
-    testing::internal::CaptureStdout();
-    code->run(ctx.get());
-    ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
-}
+        m_builder->createListAppend(globalList1.get(), m_builder->addConstValue(1));
+        m_builder->createListAppend(globalList1.get(), m_builder->addConstValue(2));
 
-TEST_F(LLVMCodeBuilderTest, VariableLoopTypeAnalysis3)
-{
-    Stage stage;
-    Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
+        m_builder->createListAppend(globalList2.get(), m_builder->addConstValue("hello"));
+        m_builder->createListAppend(globalList2.get(), m_builder->addConstValue("world"));
 
-    auto globalVar = std::make_shared<Variable>("", "");
-    stage.addVariable(globalVar);
+        m_builder->createListAppend(localList.get(), m_builder->addConstValue(false));
+        m_builder->createListAppend(localList.get(), m_builder->addConstValue(true));
+    };
 
-    auto localVar = std::make_shared<Variable>("", "");
-    sprite.addVariable(localVar);
+    auto checkLists = [this, globalList1, globalList2, localList]() {
+        CompilerValue *v = m_builder->addListItem(globalList1.get(), m_builder->addConstValue(0));
+        m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    createBuilder(&sprite, true);
+        v = m_builder->addListItem(globalList2.get(), m_builder->addConstValue(1));
+        m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    CompilerValue *v = m_builder->addConstValue(0);
-    m_builder->createVariableWrite(globalVar.get(), v);
+        v = m_builder->addListItem(localList.get(), m_builder->addConstValue(0));
+        m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    };
 
-    v = m_builder->addConstValue(5.25);
-    m_builder->createVariableWrite(localVar.get(), v);
+    // repeat (2)
+    resetLists();
 
+    CompilerValue *v, *v1, *v2;
     v = m_builder->addConstValue(2);
     m_builder->beginRepeatLoop(v);
     {
-        // Type is unknown here because a variable with unknown type is assigned (the variable has unknown type because a string is assigned later)
-        v = m_builder->addVariableValue(localVar.get());
-        m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
+        v = m_builder->addConstValue("hello world");
+        m_builder->createListAppend(globalList1.get(), v);
 
-        v = m_builder->addConstValue(2);
-        m_builder->beginRepeatLoop(v);
-        {
-            v = m_builder->addVariableValue(globalVar.get());
-            m_builder->createVariableWrite(localVar.get(), v);
+        v1 = m_builder->addConstValue(0);
+        v2 = m_builder->addConstValue(8.5);
+        m_builder->createListInsert(globalList2.get(), v1, v2);
 
-            v = m_builder->addConstValue("test");
-            m_builder->createVariableWrite(globalVar.get(), v);
-        }
-        m_builder->endLoop();
+        v1 = m_builder->addConstValue(1);
+        v2 = m_builder->addConstValue(-4.25);
+        m_builder->createListReplace(localList.get(), v1, v2);
     }
     m_builder->endLoop();
 
-    std::string expected =
-        "5.25\n"
-        "0\n";
+    checkLists();
 
-    auto code = m_builder->finalize();
-    Script script(&sprite, nullptr, nullptr);
-    script.setCode(code);
-    Thread thread(&sprite, nullptr, &script);
-    auto ctx = code->createExecutionContext(&thread);
-    testing::internal::CaptureStdout();
-    code->run(ctx.get());
-    ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
-}
+    // repeat(0)
+    resetLists();
 
-TEST_F(LLVMCodeBuilderTest, VariableLoopTypeAnalysis4)
-{
-    Stage stage;
-    Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
+    v = m_builder->addConstValue(0);
+    m_builder->beginRepeatLoop(v);
+    {
+        v = m_builder->addConstValue("hello world");
+        m_builder->createListAppend(globalList1.get(), v);
 
-    auto globalVar = std::make_shared<Variable>("", "");
-    stage.addVariable(globalVar);
+        v1 = m_builder->addConstValue(0);
+        v2 = m_builder->addConstValue(8.5);
+        m_builder->createListInsert(globalList2.get(), v1, v2);
 
-    auto localVar = std::make_shared<Variable>("", "");
-    sprite.addVariable(localVar);
+        v1 = m_builder->addConstValue(1);
+        v2 = m_builder->addConstValue(-4.25);
+        m_builder->createListReplace(localList.get(), v1, v2);
+    }
+    m_builder->endLoop();
 
-    createBuilder(&sprite, true);
+    checkLists();
 
-    CompilerValue *v = m_builder->addConstValue(0);
-    m_builder->createVariableWrite(globalVar.get(), v);
+    // while (counter1 < 5) { ... until (counter2 == 3) {... counter2++ }; while (false) { ... }; counter1++ }
+    resetLists();
 
-    v = m_builder->addConstValue(5.25);
-    m_builder->createVariableWrite(localVar.get(), v);
+    v = m_builder->addConstValue(0);
+    m_builder->createVariableWrite(counter1.get(), v);
 
-    v = m_builder->addConstValue(2);
-    m_builder->beginRepeatLoop(v);
+    m_builder->beginLoopCondition();
+    v1 = m_builder->addVariableValue(counter1.get());
+    v2 = m_builder->addConstValue(5);
+    v = m_builder->createCmpLT(v1, v2);
+    m_builder->beginWhileLoop(v);
     {
-        // Type is known here because a variable is assigned which has a number assigned later
-        v = m_builder->addVariableValue(localVar.get());
-        m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
+        v = m_builder->addConstValue(0);
+        m_builder->createVariableWrite(counter2.get(), v);
 
-        v = m_builder->addConstValue(2);
-        m_builder->beginRepeatLoop(v);
+        m_builder->beginLoopCondition();
+        v1 = m_builder->addVariableValue(counter2.get());
+        v2 = m_builder->addConstValue(3);
+        v = m_builder->createCmpEQ(v1, v2);
+        m_builder->beginRepeatUntilLoop(v);
         {
-            v = m_builder->addVariableValue(globalVar.get());
-            m_builder->createVariableWrite(localVar.get(), v);
+            v1 = m_builder->addConstValue(0);
+            v2 = m_builder->addConstValue(8.5);
+            m_builder->createListInsert(globalList2.get(), v1, v2);
 
-            v = m_builder->addConstValue(12.5);
-            m_builder->createVariableWrite(globalVar.get(), v);
+            v1 = m_builder->addConstValue(1);
+            v2 = m_builder->addConstValue(-4.25);
+            m_builder->createListReplace(localList.get(), v1, v2);
+
+            v1 = m_builder->addVariableValue(counter2.get());
+            v2 = m_builder->addConstValue(1);
+            v = m_builder->createAdd(v1, v2);
+            m_builder->createVariableWrite(counter2.get(), v);
+        }
+        m_builder->endLoop();
+
+        m_builder->beginLoopCondition();
+        v = m_builder->addConstValue(false);
+        m_builder->beginWhileLoop(v);
+        {
+            v = m_builder->addConstValue("hello world");
+            m_builder->createListAppend(globalList1.get(), v);
         }
         m_builder->endLoop();
+
+        v1 = m_builder->addVariableValue(counter1.get());
+        v2 = m_builder->addConstValue(1);
+        v = m_builder->createAdd(v1, v2);
+        m_builder->createVariableWrite(counter1.get(), v);
+    }
+    m_builder->endLoop();
+
+    checkLists();
+
+    // until (true)
+    resetLists();
+
+    m_builder->beginLoopCondition();
+    v = m_builder->addConstValue(true);
+    m_builder->beginRepeatUntilLoop(v);
+    {
+        v = m_builder->addConstValue("hello world");
+        m_builder->createListAppend(globalList1.get(), v);
+
+        v1 = m_builder->addConstValue(0);
+        v2 = m_builder->addConstValue(8.5);
+        m_builder->createListInsert(globalList2.get(), v1, v2);
+
+        v1 = m_builder->addConstValue(1);
+        v2 = m_builder->addConstValue(-4.25);
+        m_builder->createListReplace(localList.get(), v1, v2);
     }
     m_builder->endLoop();
 
+    checkLists();
+
     std::string expected =
-        "5.25\n"
-        "12.5\n";
+        "1\n"
+        "8.5\n"
+        "false\n"
+        "1\n"
+        "world\n"
+        "false\n"
+        "1\n"
+        "8.5\n"
+        "false\n"
+        "1\n"
+        "world\n"
+        "false\n";
 
     auto code = m_builder->finalize();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
+    ;
     Thread thread(&sprite, nullptr, &script);
     auto ctx = code->createExecutionContext(&thread);
     testing::internal::CaptureStdout();
@@ -4420,1529 +4460,49 @@ TEST_F(LLVMCodeBuilderTest, VariableLoopTypeAnalysis4)
     ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
 }
 
-TEST_F(LLVMCodeBuilderTest, VariableLoopTypeAnalysis5)
+TEST_F(LLVMCodeBuilderTest, ListLoopTypeAnalysis)
 {
+    // This just makes sure the type analyzer is used correctly
     Stage stage;
     Sprite sprite;
     sprite.setEngine(&m_engine);
     EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
 
-    auto globalVar = std::make_shared<Variable>("", "");
-    stage.addVariable(globalVar);
+    auto globalList = std::make_shared<List>("", "");
+    stage.addList(globalList);
 
-    auto localVar = std::make_shared<Variable>("", "");
-    sprite.addVariable(localVar);
+    auto localList = std::make_shared<List>("", "");
+    sprite.addList(localList);
 
     createBuilder(&sprite, true);
 
-    CompilerValue *v = m_builder->addConstValue("test");
-    m_builder->createVariableWrite(globalVar.get(), v);
+    m_builder->createListClear(localList.get());
 
-    v = m_builder->addConstValue(5.25);
-    m_builder->createVariableWrite(localVar.get(), v);
+    CompilerValue *v = m_builder->addConstValue(5.25);
+    m_builder->createListAppend(localList.get(), v);
 
-    v = m_builder->addConstValue(3);
+    v = m_builder->addConstValue(2);
     m_builder->beginRepeatLoop(v);
     {
-        // Type is unknown here because a string variable is assigned later which has a number assigned as well
-        v = m_builder->addVariableValue(localVar.get());
+        // Type is unknown here because a string is added later
+        v = m_builder->createSub(m_builder->addListSize(localList.get()), m_builder->addConstValue(1));
+        v = m_builder->addListItem(localList.get(), v);
         m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
 
-        v = m_builder->addVariableValue(globalVar.get());
-        m_builder->createVariableWrite(localVar.get(), v);
+        v = m_builder->addListItemIndex(localList.get(), m_builder->addConstValue(5.25));
+        m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
 
-        v = m_builder->addConstValue(12.5);
-        m_builder->createVariableWrite(globalVar.get(), v);
+        v = m_builder->addListContains(localList.get(), m_builder->addConstValue(5.25));
+        m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
+
+        v = m_builder->addConstValue("test");
+        m_builder->createListAppend(localList.get(), v);
     }
     m_builder->endLoop();
 
     std::string expected =
         "5.25\n"
         "0\n"
-        "12.5\n";
-
-    auto code = m_builder->finalize();
-    Script script(&sprite, nullptr, nullptr);
-    script.setCode(code);
-    Thread thread(&sprite, nullptr, &script);
-    auto ctx = code->createExecutionContext(&thread);
-    testing::internal::CaptureStdout();
-    code->run(ctx.get());
-    ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
-}
-
-TEST_F(LLVMCodeBuilderTest, VariableLoopTypeAnalysis6)
-{
-    Stage stage;
-    Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
-
-    auto globalVar = std::make_shared<Variable>("", "");
-    stage.addVariable(globalVar);
-
-    auto localVar = std::make_shared<Variable>("", "");
-    sprite.addVariable(localVar);
-
-    createBuilder(&sprite, true);
-
-    CompilerValue *v = m_builder->addConstValue(5.25);
-    m_builder->createVariableWrite(localVar.get(), v);
-
-    v = m_builder->addConstValue(2);
-    m_builder->beginRepeatLoop(v);
-    {
-        // Type is known here because a variable with known type is assigned later (even though the variable has a string assigned later, there's a number assigned before the read operation)
-        v = m_builder->addVariableValue(localVar.get());
-        m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
-
-        v = m_builder->addConstValue(2);
-        m_builder->beginRepeatLoop(v);
-        {
-            v = m_builder->addConstValue(10);
-            m_builder->createVariableWrite(globalVar.get(), v);
-
-            v = m_builder->addVariableValue(globalVar.get());
-            m_builder->createVariableWrite(localVar.get(), v);
-
-            v = m_builder->addConstValue("test");
-            m_builder->createVariableWrite(globalVar.get(), v);
-        }
-        m_builder->endLoop();
-    }
-    m_builder->endLoop();
-
-    std::string expected =
-        "5.25\n"
-        "10\n";
-
-    auto code = m_builder->finalize();
-    Script script(&sprite, nullptr, nullptr);
-    script.setCode(code);
-    Thread thread(&sprite, nullptr, &script);
-    auto ctx = code->createExecutionContext(&thread);
-    testing::internal::CaptureStdout();
-    code->run(ctx.get());
-    ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
-}
-
-TEST_F(LLVMCodeBuilderTest, VariableLoopTypeAnalysis7)
-{
-    Stage stage;
-    Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
-
-    auto globalVar = std::make_shared<Variable>("", "");
-    stage.addVariable(globalVar);
-
-    auto localVar = std::make_shared<Variable>("", "");
-    sprite.addVariable(localVar);
-
-    createBuilder(&sprite, true);
-
-    CompilerValue *v = m_builder->addConstValue(5.25);
-    m_builder->createVariableWrite(localVar.get(), v);
-
-    v = m_builder->addConstValue(2);
-    m_builder->beginRepeatLoop(v);
-    {
-        // Type is unknown here because a variable with a known, but different type is assigned later
-        v = m_builder->addVariableValue(localVar.get());
-        m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
-
-        v = m_builder->addConstValue(2);
-        m_builder->beginRepeatLoop(v);
-        {
-            v = m_builder->addConstValue("test");
-            m_builder->createVariableWrite(globalVar.get(), v);
-
-            v = m_builder->addVariableValue(globalVar.get());
-            m_builder->createVariableWrite(localVar.get(), v);
-
-            v = m_builder->addConstValue(10);
-            m_builder->createVariableWrite(globalVar.get(), v);
-        }
-        m_builder->endLoop();
-    }
-    m_builder->endLoop();
-
-    std::string expected =
-        "5.25\n"
-        "0\n";
-
-    auto code = m_builder->finalize();
-    Script script(&sprite, nullptr, nullptr);
-    script.setCode(code);
-    Thread thread(&sprite, nullptr, &script);
-    auto ctx = code->createExecutionContext(&thread);
-    testing::internal::CaptureStdout();
-    code->run(ctx.get());
-    ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
-}
-
-TEST_F(LLVMCodeBuilderTest, VariableLoopTypeAnalysis8)
-{
-    Stage stage;
-    Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
-
-    auto globalVar = std::make_shared<Variable>("", "");
-    stage.addVariable(globalVar);
-
-    auto localVar = std::make_shared<Variable>("", "");
-    sprite.addVariable(localVar);
-
-    createBuilder(&sprite, true);
-
-    CompilerValue *v = m_builder->addConstValue(5.25);
-    m_builder->createVariableWrite(localVar.get(), v);
-
-    v = m_builder->addConstValue(2);
-    m_builder->beginRepeatLoop(v);
-    {
-        // Type is unknown here because a variable with a known, but different type is assigned later
-        v = m_builder->addVariableValue(localVar.get());
-        m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
-
-        v = m_builder->addConstValue(2);
-        m_builder->beginRepeatLoop(v);
-        {
-            v = m_builder->addConstValue("test");
-            m_builder->createVariableWrite(globalVar.get(), v);
-
-            v = m_builder->addVariableValue(globalVar.get());
-            m_builder->createVariableWrite(localVar.get(), v);
-        }
-        m_builder->endLoop();
-    }
-    m_builder->endLoop();
-
-    std::string expected =
-        "5.25\n"
-        "0\n";
-
-    auto code = m_builder->finalize();
-    Script script(&sprite, nullptr, nullptr);
-    script.setCode(code);
-    Thread thread(&sprite, nullptr, &script);
-    auto ctx = code->createExecutionContext(&thread);
-    testing::internal::CaptureStdout();
-    code->run(ctx.get());
-    ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
-}
-
-TEST_F(LLVMCodeBuilderTest, VariableLoopTypeAnalysis9)
-{
-    Stage stage;
-    Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
-
-    auto globalVar = std::make_shared<Variable>("", "", "123");
-    stage.addVariable(globalVar);
-
-    auto localVar = std::make_shared<Variable>("", "");
-    sprite.addVariable(localVar);
-
-    createBuilder(&sprite, true);
-
-    CompilerValue *v = m_builder->addConstValue(5.25);
-    m_builder->createVariableWrite(localVar.get(), v);
-
-    v = m_builder->addConstValue(2);
-    m_builder->beginRepeatLoop(v);
-    {
-        v = m_builder->addConstValue(2);
-        m_builder->beginRepeatLoop(v);
-        {
-            v = m_builder->addVariableValue(globalVar.get());
-            m_builder->createVariableWrite(localVar.get(), v);
-
-            v = m_builder->addConstValue(5);
-            m_builder->createVariableWrite(globalVar.get(), v);
-        }
-        m_builder->endLoop();
-
-        // Type is unknown here because a variable of unknown type is assigned before the read operation
-        v = m_builder->addVariableValue(localVar.get());
-        m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
-
-        v = m_builder->addConstValue(2);
-        m_builder->beginRepeatLoop(v);
-        {
-            v = m_builder->addConstValue(10);
-            m_builder->createVariableWrite(globalVar.get(), v);
-
-            v = m_builder->addVariableValue(globalVar.get());
-            m_builder->createVariableWrite(localVar.get(), v);
-
-            v = m_builder->addConstValue("test");
-            m_builder->createVariableWrite(globalVar.get(), v);
-        }
-        m_builder->endLoop();
-    }
-    m_builder->endLoop();
-
-    std::string expected =
-        "5\n"
-        "5\n";
-
-    auto code = m_builder->finalize();
-    Script script(&sprite, nullptr, nullptr);
-    script.setCode(code);
-    Thread thread(&sprite, nullptr, &script);
-    auto ctx = code->createExecutionContext(&thread);
-    testing::internal::CaptureStdout();
-    code->run(ctx.get());
-    ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
-}
-
-TEST_F(LLVMCodeBuilderTest, VariableLoopTypeAnalysis10)
-{
-    Stage stage;
-    Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
-
-    auto globalVar = std::make_shared<Variable>("", "");
-    stage.addVariable(globalVar);
-
-    auto localVar = std::make_shared<Variable>("", "", "123");
-    sprite.addVariable(localVar);
-
-    createBuilder(&sprite, true);
-
-    CompilerValue *v = m_builder->addConstValue(2);
-    m_builder->beginRepeatLoop(v);
-    {
-        v = m_builder->addConstValue("test");
-        m_builder->createVariableWrite(globalVar.get(), v);
-
-        v = m_builder->addConstValue(3);
-        m_builder->beginRepeatLoop(v);
-        {
-            // Type is unknown here because a variable of unknown type is assigned later
-            v = m_builder->addVariableValue(localVar.get());
-            m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
-
-            v = m_builder->addVariableValue(globalVar.get());
-            m_builder->createVariableWrite(localVar.get(), v);
-
-            v = m_builder->addConstValue(12.5);
-            m_builder->createVariableWrite(globalVar.get(), v);
-        }
-        m_builder->endLoop();
-    }
-    m_builder->endLoop();
-
-    std::string expected =
-        "123\n"
-        "0\n"
-        "12.5\n"
-        "12.5\n"
-        "0\n"
-        "12.5\n";
-
-    auto code = m_builder->finalize();
-    Script script(&sprite, nullptr, nullptr);
-    script.setCode(code);
-    Thread thread(&sprite, nullptr, &script);
-    auto ctx = code->createExecutionContext(&thread);
-    testing::internal::CaptureStdout();
-    code->run(ctx.get());
-    ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
-}
-
-TEST_F(LLVMCodeBuilderTest, VariableLoopTypeAnalysis11)
-{
-    Stage stage;
-    Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
-
-    auto globalVar = std::make_shared<Variable>("", "");
-    stage.addVariable(globalVar);
-
-    auto localVar = std::make_shared<Variable>("", "", "123");
-    sprite.addVariable(localVar);
-
-    createBuilder(&sprite, true);
-
-    CompilerValue *v = m_builder->addConstValue(2);
-    m_builder->beginRepeatLoop(v);
-    {
-        v = m_builder->addConstValue("test");
-        m_builder->createVariableWrite(globalVar.get(), v);
-
-        v = m_builder->addConstValue(3);
-        m_builder->beginRepeatLoop(v);
-        {
-            // Type is unknown here because the variable is assigned to itself later
-            // This case is not checked because the code isn't considered valid
-            v = m_builder->addVariableValue(localVar.get());
-            m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
-
-            v = m_builder->addVariableValue(localVar.get());
-            m_builder->createVariableWrite(localVar.get(), v);
-
-            v = m_builder->addConstValue(12.5);
-            m_builder->createVariableWrite(globalVar.get(), v);
-        }
-        m_builder->endLoop();
-    }
-    m_builder->endLoop();
-
-    std::string expected =
-        "123\n"
-        "123\n"
-        "123\n"
-        "123\n"
-        "123\n"
-        "123\n";
-
-    auto code = m_builder->finalize();
-    Script script(&sprite, nullptr, nullptr);
-    script.setCode(code);
-    Thread thread(&sprite, nullptr, &script);
-    auto ctx = code->createExecutionContext(&thread);
-    testing::internal::CaptureStdout();
-    code->run(ctx.get());
-    ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
-}
-
-TEST_F(LLVMCodeBuilderTest, VariableLoopTypeAnalysis12)
-{
-    Stage stage;
-    Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
-
-    auto globalVar = std::make_shared<Variable>("", "");
-    stage.addVariable(globalVar);
-
-    auto localVar = std::make_shared<Variable>("", "", "123");
-    sprite.addVariable(localVar);
-
-    createBuilder(&sprite, true);
-
-    CompilerValue *v = m_builder->addConstValue(2);
-    m_builder->beginRepeatLoop(v);
-    {
-        v = m_builder->addConstValue("test");
-        m_builder->createVariableWrite(globalVar.get(), v);
-
-        v = m_builder->addConstValue(3);
-        m_builder->beginRepeatLoop(v);
-        {
-            // Type is unknown here because another variable is assigned later, but it has this variable assigned
-            // This case is not checked because the code isn't considered valid
-            v = m_builder->addVariableValue(localVar.get());
-            m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
-
-            v = m_builder->addVariableValue(globalVar.get());
-            m_builder->createVariableWrite(localVar.get(), v);
-
-            v = m_builder->addVariableValue(localVar.get());
-            m_builder->createVariableWrite(globalVar.get(), v);
-        }
-        m_builder->endLoop();
-    }
-    m_builder->endLoop();
-
-    std::string expected =
-        "123\n"
-        "0\n"
-        "0\n"
-        "0\n"
-        "0\n"
-        "0\n";
-
-    auto code = m_builder->finalize();
-    Script script(&sprite, nullptr, nullptr);
-    script.setCode(code);
-    Thread thread(&sprite, nullptr, &script);
-    auto ctx = code->createExecutionContext(&thread);
-    testing::internal::CaptureStdout();
-    code->run(ctx.get());
-    ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
-}
-
-TEST_F(LLVMCodeBuilderTest, LoopLists)
-{
-    Stage stage;
-    Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
-
-    auto globalList1 = std::make_shared<List>("", "");
-    stage.addList(globalList1);
-
-    auto globalList2 = std::make_shared<List>("", "");
-    stage.addList(globalList2);
-
-    auto localList = std::make_shared<List>("", "");
-    sprite.addList(localList);
-
-    auto counter1 = std::make_shared<Variable>("", "");
-    auto counter2 = std::make_shared<Variable>("", "");
-    sprite.addVariable(counter1);
-    sprite.addVariable(counter2);
-
-    createBuilder(&sprite, true);
-
-    auto resetLists = [this, globalList1, globalList2, localList]() {
-        m_builder->createListClear(globalList1.get());
-        m_builder->createListClear(globalList2.get());
-        m_builder->createListClear(localList.get());
-
-        m_builder->createListAppend(globalList1.get(), m_builder->addConstValue(1));
-        m_builder->createListAppend(globalList1.get(), m_builder->addConstValue(2));
-
-        m_builder->createListAppend(globalList2.get(), m_builder->addConstValue("hello"));
-        m_builder->createListAppend(globalList2.get(), m_builder->addConstValue("world"));
-
-        m_builder->createListAppend(localList.get(), m_builder->addConstValue(false));
-        m_builder->createListAppend(localList.get(), m_builder->addConstValue(true));
-    };
-
-    auto checkLists = [this, globalList1, globalList2, localList]() {
-        CompilerValue *v = m_builder->addListItem(globalList1.get(), m_builder->addConstValue(0));
-        m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
-
-        v = m_builder->addListItem(globalList2.get(), m_builder->addConstValue(1));
-        m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
-
-        v = m_builder->addListItem(localList.get(), m_builder->addConstValue(0));
-        m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
-    };
-
-    // repeat (2)
-    resetLists();
-
-    CompilerValue *v, *v1, *v2;
-    v = m_builder->addConstValue(2);
-    m_builder->beginRepeatLoop(v);
-    {
-        v = m_builder->addConstValue("hello world");
-        m_builder->createListAppend(globalList1.get(), v);
-
-        v1 = m_builder->addConstValue(0);
-        v2 = m_builder->addConstValue(8.5);
-        m_builder->createListInsert(globalList2.get(), v1, v2);
-
-        v1 = m_builder->addConstValue(1);
-        v2 = m_builder->addConstValue(-4.25);
-        m_builder->createListReplace(localList.get(), v1, v2);
-    }
-    m_builder->endLoop();
-
-    checkLists();
-
-    // repeat(0)
-    resetLists();
-
-    v = m_builder->addConstValue(0);
-    m_builder->beginRepeatLoop(v);
-    {
-        v = m_builder->addConstValue("hello world");
-        m_builder->createListAppend(globalList1.get(), v);
-
-        v1 = m_builder->addConstValue(0);
-        v2 = m_builder->addConstValue(8.5);
-        m_builder->createListInsert(globalList2.get(), v1, v2);
-
-        v1 = m_builder->addConstValue(1);
-        v2 = m_builder->addConstValue(-4.25);
-        m_builder->createListReplace(localList.get(), v1, v2);
-    }
-    m_builder->endLoop();
-
-    checkLists();
-
-    // while (counter1 < 5) { ... until (counter2 == 3) {... counter2++ }; while (false) { ... }; counter1++ }
-    resetLists();
-
-    v = m_builder->addConstValue(0);
-    m_builder->createVariableWrite(counter1.get(), v);
-
-    m_builder->beginLoopCondition();
-    v1 = m_builder->addVariableValue(counter1.get());
-    v2 = m_builder->addConstValue(5);
-    v = m_builder->createCmpLT(v1, v2);
-    m_builder->beginWhileLoop(v);
-    {
-        v = m_builder->addConstValue(0);
-        m_builder->createVariableWrite(counter2.get(), v);
-
-        m_builder->beginLoopCondition();
-        v1 = m_builder->addVariableValue(counter2.get());
-        v2 = m_builder->addConstValue(3);
-        v = m_builder->createCmpEQ(v1, v2);
-        m_builder->beginRepeatUntilLoop(v);
-        {
-            v1 = m_builder->addConstValue(0);
-            v2 = m_builder->addConstValue(8.5);
-            m_builder->createListInsert(globalList2.get(), v1, v2);
-
-            v1 = m_builder->addConstValue(1);
-            v2 = m_builder->addConstValue(-4.25);
-            m_builder->createListReplace(localList.get(), v1, v2);
-
-            v1 = m_builder->addVariableValue(counter2.get());
-            v2 = m_builder->addConstValue(1);
-            v = m_builder->createAdd(v1, v2);
-            m_builder->createVariableWrite(counter2.get(), v);
-        }
-        m_builder->endLoop();
-
-        m_builder->beginLoopCondition();
-        v = m_builder->addConstValue(false);
-        m_builder->beginWhileLoop(v);
-        {
-            v = m_builder->addConstValue("hello world");
-            m_builder->createListAppend(globalList1.get(), v);
-        }
-        m_builder->endLoop();
-
-        v1 = m_builder->addVariableValue(counter1.get());
-        v2 = m_builder->addConstValue(1);
-        v = m_builder->createAdd(v1, v2);
-        m_builder->createVariableWrite(counter1.get(), v);
-    }
-    m_builder->endLoop();
-
-    checkLists();
-
-    // until (true)
-    resetLists();
-
-    m_builder->beginLoopCondition();
-    v = m_builder->addConstValue(true);
-    m_builder->beginRepeatUntilLoop(v);
-    {
-        v = m_builder->addConstValue("hello world");
-        m_builder->createListAppend(globalList1.get(), v);
-
-        v1 = m_builder->addConstValue(0);
-        v2 = m_builder->addConstValue(8.5);
-        m_builder->createListInsert(globalList2.get(), v1, v2);
-
-        v1 = m_builder->addConstValue(1);
-        v2 = m_builder->addConstValue(-4.25);
-        m_builder->createListReplace(localList.get(), v1, v2);
-    }
-    m_builder->endLoop();
-
-    checkLists();
-
-    std::string expected =
-        "1\n"
-        "8.5\n"
-        "false\n"
-        "1\n"
-        "world\n"
-        "false\n"
-        "1\n"
-        "8.5\n"
-        "false\n"
-        "1\n"
-        "world\n"
-        "false\n";
-
-    auto code = m_builder->finalize();
-    Script script(&sprite, nullptr, nullptr);
-    script.setCode(code);
-    ;
-    Thread thread(&sprite, nullptr, &script);
-    auto ctx = code->createExecutionContext(&thread);
-    testing::internal::CaptureStdout();
-    code->run(ctx.get());
-    ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
-}
-
-TEST_F(LLVMCodeBuilderTest, ListLoopTypeAnalysis1)
-{
-    Stage stage;
-    Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
-
-    auto globalList = std::make_shared<List>("", "");
-    stage.addList(globalList);
-
-    auto localList = std::make_shared<List>("", "");
-    sprite.addList(localList);
-
-    createBuilder(&sprite, true);
-
-    m_builder->createListClear(localList.get());
-
-    CompilerValue *v = m_builder->addConstValue(5.25);
-    m_builder->createListAppend(localList.get(), v);
-
-    v = m_builder->addConstValue(2);
-    m_builder->beginRepeatLoop(v);
-    {
-        // Type is unknown here because a string is added later
-        v = m_builder->createSub(m_builder->addListSize(localList.get()), m_builder->addConstValue(1));
-        v = m_builder->addListItem(localList.get(), v);
-        m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
-
-        v = m_builder->addListItemIndex(localList.get(), m_builder->addConstValue(5.25));
-        m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
-
-        v = m_builder->addListContains(localList.get(), m_builder->addConstValue(5.25));
-        m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
-
-        v = m_builder->addConstValue("test");
-        m_builder->createListAppend(localList.get(), v);
-    }
-    m_builder->endLoop();
-
-    std::string expected =
-        "5.25\n"
-        "0\n"
-        "1\n"
-        "0\n"
-        "0\n"
-        "1\n";
-
-    auto code = m_builder->finalize();
-    Script script(&sprite, nullptr, nullptr);
-    script.setCode(code);
-    Thread thread(&sprite, nullptr, &script);
-    auto ctx = code->createExecutionContext(&thread);
-    testing::internal::CaptureStdout();
-    code->run(ctx.get());
-    ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
-}
-
-TEST_F(LLVMCodeBuilderTest, ListLoopTypeAnalysis2)
-{
-    Stage stage;
-    Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
-
-    auto globalList = std::make_shared<List>("", "");
-    stage.addList(globalList);
-
-    auto localList = std::make_shared<List>("", "");
-    sprite.addList(localList);
-
-    createBuilder(&sprite, true);
-
-    m_builder->createListClear(localList.get());
-
-    CompilerValue *v = m_builder->addConstValue(5.25);
-    m_builder->createListAppend(localList.get(), v);
-
-    v = m_builder->addConstValue(2);
-    m_builder->beginRepeatLoop(v);
-    {
-        // Type is known here because a number is assigned later
-        v = m_builder->addConstValue(0);
-        v = m_builder->addListItem(localList.get(), v);
-        m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
-
-        v = m_builder->addListItemIndex(localList.get(), m_builder->addConstValue(5.25));
-        m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
-
-        v = m_builder->addListContains(localList.get(), m_builder->addConstValue(5.25));
-        m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
-
-        v = m_builder->addConstValue(12.5);
-        m_builder->createListReplace(localList.get(), m_builder->addConstValue(0), v);
-    }
-    m_builder->endLoop();
-
-    std::string expected =
-        "5.25\n"
-        "0\n"
-        "1\n"
-        "12.5\n"
-        "-1\n"
-        "0\n";
-
-    auto code = m_builder->finalize();
-    Script script(&sprite, nullptr, nullptr);
-    script.setCode(code);
-    Thread thread(&sprite, nullptr, &script);
-    auto ctx = code->createExecutionContext(&thread);
-    testing::internal::CaptureStdout();
-    code->run(ctx.get());
-    ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
-}
-
-TEST_F(LLVMCodeBuilderTest, ListLoopTypeAnalysis3)
-{
-    Stage stage;
-    Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
-
-    auto globalList = std::make_shared<List>("", "");
-    stage.addList(globalList);
-
-    auto localList = std::make_shared<List>("", "");
-    sprite.addList(localList);
-
-    createBuilder(&sprite, true);
-
-    m_builder->createListClear(globalList.get());
-    m_builder->createListClear(localList.get());
-
-    CompilerValue *v = m_builder->addConstValue(0);
-    m_builder->createListAppend(globalList.get(), v);
-
-    v = m_builder->addConstValue(5.25);
-    m_builder->createListAppend(localList.get(), v);
-
-    v = m_builder->addConstValue(2);
-    m_builder->beginRepeatLoop(v);
-    {
-        // Type is unknown here because a list item with unknown type is inserted (the item has unknown type because a string is assigned later)
-        v = m_builder->addConstValue(0);
-        v = m_builder->addListItem(localList.get(), v);
-        m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
-
-        v = m_builder->addListItemIndex(localList.get(), m_builder->addConstValue(5.25));
-        m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
-
-        v = m_builder->addListContains(localList.get(), m_builder->addConstValue(5.25));
-        m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
-
-        v = m_builder->addConstValue(2);
-        m_builder->beginRepeatLoop(v);
-        {
-            v = m_builder->addListItem(globalList.get(), m_builder->addConstValue(0));
-            m_builder->createListInsert(localList.get(), m_builder->addConstValue(0), v);
-
-            v = m_builder->addConstValue("test");
-            m_builder->createListReplace(globalList.get(), m_builder->addConstValue(0), v);
-        }
-        m_builder->endLoop();
-    }
-    m_builder->endLoop();
-
-    std::string expected =
-        "5.25\n"
-        "0\n"
-        "1\n"
-        "0\n"
-        "2\n"
-        "1\n";
-
-    auto code = m_builder->finalize();
-    Script script(&sprite, nullptr, nullptr);
-    script.setCode(code);
-    Thread thread(&sprite, nullptr, &script);
-    auto ctx = code->createExecutionContext(&thread);
-    testing::internal::CaptureStdout();
-    code->run(ctx.get());
-    ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
-}
-
-TEST_F(LLVMCodeBuilderTest, ListLoopTypeAnalysis4)
-{
-    Stage stage;
-    Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
-
-    auto globalList = std::make_shared<List>("", "");
-    stage.addList(globalList);
-
-    auto localList = std::make_shared<List>("", "");
-    sprite.addList(localList);
-
-    createBuilder(&sprite, true);
-
-    m_builder->createListClear(globalList.get());
-    m_builder->createListClear(localList.get());
-
-    CompilerValue *v = m_builder->addConstValue(0);
-    m_builder->createListAppend(globalList.get(), v);
-
-    v = m_builder->addConstValue(5.25);
-    m_builder->createListAppend(localList.get(), v);
-
-    v = m_builder->addConstValue(2);
-    m_builder->beginRepeatLoop(v);
-    {
-        // Type is known here because a number list item is added later
-        v = m_builder->createSub(m_builder->addListSize(localList.get()), m_builder->addConstValue(1));
-        v = m_builder->addListItem(localList.get(), v);
-        m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
-
-        v = m_builder->addListItemIndex(localList.get(), m_builder->addConstValue(5.25));
-        m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
-
-        v = m_builder->addListContains(localList.get(), m_builder->addConstValue(5.25));
-        m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
-
-        v = m_builder->addConstValue(2);
-        m_builder->beginRepeatLoop(v);
-        {
-            v = m_builder->addListItem(globalList.get(), m_builder->addConstValue(0));
-            m_builder->createListAppend(localList.get(), v);
-
-            v = m_builder->addConstValue(12.5);
-            m_builder->createListInsert(globalList.get(), m_builder->addConstValue(0), v);
-        }
-        m_builder->endLoop();
-    }
-    m_builder->endLoop();
-
-    std::string expected =
-        "5.25\n"
-        "0\n"
-        "1\n"
-        "12.5\n"
-        "0\n"
-        "1\n";
-
-    auto code = m_builder->finalize();
-    Script script(&sprite, nullptr, nullptr);
-    script.setCode(code);
-    Thread thread(&sprite, nullptr, &script);
-    auto ctx = code->createExecutionContext(&thread);
-    testing::internal::CaptureStdout();
-    code->run(ctx.get());
-    ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
-}
-
-TEST_F(LLVMCodeBuilderTest, ListLoopTypeAnalysis5)
-{
-    Stage stage;
-    Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
-
-    auto globalList = std::make_shared<List>("", "");
-    stage.addList(globalList);
-
-    auto localList = std::make_shared<List>("", "");
-    sprite.addList(localList);
-
-    createBuilder(&sprite, true);
-
-    m_builder->createListClear(globalList.get());
-    m_builder->createListClear(localList.get());
-
-    CompilerValue *v = m_builder->addConstValue("test");
-    m_builder->createListAppend(globalList.get(), v);
-
-    v = m_builder->addConstValue(5.25);
-    m_builder->createListAppend(localList.get(), v);
-
-    v = m_builder->addConstValue(3);
-    m_builder->beginRepeatLoop(v);
-    {
-        // Type is unknown here because a string list item is assigned later which becomes a number later
-        v = m_builder->addConstValue(0);
-        v = m_builder->addListItem(localList.get(), v);
-        m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
-
-        v = m_builder->addListItemIndex(localList.get(), m_builder->addConstValue(5.25));
-        m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
-
-        v = m_builder->addListContains(localList.get(), m_builder->addConstValue(5.25));
-        m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
-
-        v = m_builder->addListItem(globalList.get(), m_builder->addConstValue(0));
-        m_builder->createListReplace(localList.get(), m_builder->addConstValue(0), v);
-
-        v = m_builder->addConstValue(12.5);
-        m_builder->createListReplace(globalList.get(), m_builder->addConstValue(0), v);
-    }
-    m_builder->endLoop();
-
-    std::string expected =
-        "5.25\n"
-        "0\n"
-        "1\n"
-        "0\n"
-        "-1\n"
-        "0\n"
-        "12.5\n"
-        "-1\n"
-        "0\n";
-
-    auto code = m_builder->finalize();
-    Script script(&sprite, nullptr, nullptr);
-    script.setCode(code);
-    Thread thread(&sprite, nullptr, &script);
-    auto ctx = code->createExecutionContext(&thread);
-    testing::internal::CaptureStdout();
-    code->run(ctx.get());
-    ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
-}
-
-TEST_F(LLVMCodeBuilderTest, ListLoopTypeAnalysis6)
-{
-    Stage stage;
-    Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
-
-    auto globalList = std::make_shared<List>("", "");
-    stage.addList(globalList);
-
-    auto localList = std::make_shared<List>("", "");
-    sprite.addList(localList);
-
-    createBuilder(&sprite, true);
-
-    m_builder->createListClear(globalList.get());
-    m_builder->createListClear(localList.get());
-
-    CompilerValue *v = m_builder->addConstValue(-156.07);
-    m_builder->createListAppend(globalList.get(), v);
-
-    v = m_builder->addConstValue(5.25);
-    m_builder->createListAppend(localList.get(), v);
-
-    v = m_builder->addConstValue(2);
-    m_builder->beginRepeatLoop(v);
-    {
-        // Type is unknown here because a list item with unknown type is added later
-        v = m_builder->createSub(m_builder->addListSize(localList.get()), m_builder->addConstValue(1));
-        v = m_builder->addListItem(localList.get(), v);
-        m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
-
-        v = m_builder->addListItemIndex(localList.get(), m_builder->addConstValue(5.25));
-        m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
-
-        v = m_builder->addListContains(localList.get(), m_builder->addConstValue(5.25));
-        m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
-
-        v = m_builder->addConstValue(2);
-        m_builder->beginRepeatLoop(v);
-        {
-            v = m_builder->addConstValue(10);
-            m_builder->createListReplace(globalList.get(), m_builder->addConstValue(0), v);
-
-            v = m_builder->createSub(m_builder->addListSize(globalList.get()), m_builder->addConstValue(1));
-            v = m_builder->addListItem(globalList.get(), v);
-            m_builder->createListAppend(localList.get(), v);
-
-            v = m_builder->addConstValue("test");
-            m_builder->createListAppend(globalList.get(), v);
-        }
-        m_builder->endLoop();
-    }
-    m_builder->endLoop();
-
-    std::string expected =
-        "5.25\n"
-        "0\n"
-        "1\n"
-        "0\n"
-        "0\n"
-        "1\n";
-
-    auto code = m_builder->finalize();
-    Script script(&sprite, nullptr, nullptr);
-    script.setCode(code);
-    Thread thread(&sprite, nullptr, &script);
-    auto ctx = code->createExecutionContext(&thread);
-    testing::internal::CaptureStdout();
-    code->run(ctx.get());
-    ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
-}
-
-TEST_F(LLVMCodeBuilderTest, ListLoopTypeAnalysis7)
-{
-    Stage stage;
-    Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
-
-    auto globalList = std::make_shared<List>("", "");
-    stage.addList(globalList);
-
-    auto localList = std::make_shared<List>("", "");
-    sprite.addList(localList);
-
-    createBuilder(&sprite, true);
-
-    m_builder->createListClear(localList.get());
-
-    CompilerValue *v = m_builder->addConstValue(5.25);
-    m_builder->createListAppend(localList.get(), v);
-
-    v = m_builder->addConstValue(2);
-    m_builder->beginRepeatLoop(v);
-    {
-        // Type is unknown here because a list item with unknown type is assigned later
-        v = m_builder->addConstValue(0);
-        v = m_builder->addListItem(localList.get(), v);
-        m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
-
-        v = m_builder->addListItemIndex(localList.get(), m_builder->addConstValue(5.25));
-        m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
-
-        v = m_builder->addListContains(localList.get(), m_builder->addConstValue(5.25));
-        m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
-
-        v = m_builder->addConstValue(2);
-        m_builder->beginRepeatLoop(v);
-        {
-            v = m_builder->addConstValue("test");
-            m_builder->createListInsert(globalList.get(), m_builder->addConstValue(0), v);
-
-            v = m_builder->addListItem(globalList.get(), m_builder->addConstValue(0));
-            m_builder->createListReplace(localList.get(), m_builder->addConstValue(0), v);
-
-            v = m_builder->addConstValue(10);
-            m_builder->createListReplace(globalList.get(), m_builder->addConstValue(0), v);
-        }
-        m_builder->endLoop();
-    }
-    m_builder->endLoop();
-
-    std::string expected =
-        "5.25\n"
-        "0\n"
-        "1\n"
-        "0\n"
-        "-1\n"
-        "0\n";
-
-    auto code = m_builder->finalize();
-    Script script(&sprite, nullptr, nullptr);
-    script.setCode(code);
-    Thread thread(&sprite, nullptr, &script);
-    auto ctx = code->createExecutionContext(&thread);
-    testing::internal::CaptureStdout();
-    code->run(ctx.get());
-    ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
-}
-
-TEST_F(LLVMCodeBuilderTest, ListLoopTypeAnalysis8)
-{
-    Stage stage;
-    Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
-
-    auto globalList = std::make_shared<List>("", "");
-    stage.addList(globalList);
-
-    auto localList = std::make_shared<List>("", "");
-    sprite.addList(localList);
-
-    createBuilder(&sprite, true);
-
-    m_builder->createListClear(localList.get());
-
-    CompilerValue *v = m_builder->addConstValue(5.25);
-    m_builder->createListAppend(localList.get(), v);
-
-    v = m_builder->addConstValue(2);
-    m_builder->beginRepeatLoop(v);
-    {
-        // Type is unknown here because a list item with a unknown type is assigned later
-        v = m_builder->addConstValue(0);
-        v = m_builder->addListItem(localList.get(), v);
-        m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
-
-        v = m_builder->addListItemIndex(localList.get(), m_builder->addConstValue(5.25));
-        m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
-
-        v = m_builder->addListContains(localList.get(), m_builder->addConstValue(5.25));
-        m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
-
-        v = m_builder->addConstValue(2);
-        m_builder->beginRepeatLoop(v);
-        {
-            v = m_builder->addConstValue("test");
-            m_builder->createListInsert(globalList.get(), m_builder->addConstValue(0), v);
-
-            v = m_builder->addListItem(globalList.get(), m_builder->addConstValue(0));
-            m_builder->createListReplace(localList.get(), m_builder->addConstValue(0), v);
-        }
-        m_builder->endLoop();
-    }
-    m_builder->endLoop();
-
-    std::string expected =
-        "5.25\n"
-        "0\n"
-        "1\n"
-        "0\n"
-        "-1\n"
-        "0\n";
-
-    auto code = m_builder->finalize();
-    Script script(&sprite, nullptr, nullptr);
-    script.setCode(code);
-    Thread thread(&sprite, nullptr, &script);
-    auto ctx = code->createExecutionContext(&thread);
-    testing::internal::CaptureStdout();
-    code->run(ctx.get());
-    ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
-}
-
-TEST_F(LLVMCodeBuilderTest, ListLoopTypeAnalysis9)
-{
-    Stage stage;
-    Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
-
-    auto globalList = std::make_shared<List>("", "");
-    stage.addList(globalList);
-
-    auto localList = std::make_shared<List>("", "");
-    sprite.addList(localList);
-
-    createBuilder(&sprite, true);
-
-    m_builder->createListClear(localList.get());
-
-    CompilerValue *v = m_builder->addConstValue(5.25);
-    m_builder->createListAppend(localList.get(), v);
-
-    v = m_builder->addConstValue(2);
-    m_builder->beginRepeatLoop(v);
-    {
-        v = m_builder->addConstValue(2);
-        m_builder->beginRepeatLoop(v);
-        {
-            v = m_builder->addListItem(globalList.get(), m_builder->addConstValue(0));
-            m_builder->createListReplace(localList.get(), m_builder->addConstValue(0), v);
-
-            v = m_builder->addConstValue(5);
-            m_builder->createListInsert(globalList.get(), m_builder->addConstValue(0), v);
-        }
-        m_builder->endLoop();
-
-        // Type is unknown here because a list item with unknown type is assigned before the read operation
-        v = m_builder->addListItem(localList.get(), m_builder->addConstValue(0));
-        m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
-
-        v = m_builder->addListItemIndex(localList.get(), m_builder->addConstValue(5));
-        m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
-
-        v = m_builder->addListContains(localList.get(), m_builder->addConstValue(5));
-        m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
-
-        v = m_builder->addConstValue(2);
-        m_builder->beginRepeatLoop(v);
-        {
-            v = m_builder->addConstValue(10);
-            m_builder->createListInsert(globalList.get(), m_builder->addConstValue(0), v);
-
-            v = m_builder->addListItem(globalList.get(), m_builder->addConstValue(0));
-            m_builder->createListReplace(localList.get(), m_builder->addConstValue(0), v);
-
-            v = m_builder->addConstValue("test");
-            m_builder->createListInsert(globalList.get(), m_builder->addConstValue(0), v);
-        }
-        m_builder->endLoop();
-    }
-    m_builder->endLoop();
-
-    std::string expected =
-        "5\n"
-        "0\n"
-        "1\n"
-        "5\n"
-        "0\n"
-        "1\n";
-
-    auto code = m_builder->finalize();
-    Script script(&sprite, nullptr, nullptr);
-    script.setCode(code);
-    Thread thread(&sprite, nullptr, &script);
-    auto ctx = code->createExecutionContext(&thread);
-    testing::internal::CaptureStdout();
-    code->run(ctx.get());
-    ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
-}
-
-TEST_F(LLVMCodeBuilderTest, ListLoopTypeAnalysis10)
-{
-    Stage stage;
-    Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
-
-    auto globalList = std::make_shared<List>("", "");
-    stage.addList(globalList);
-
-    auto localList = std::make_shared<List>("", "");
-    sprite.addList(localList);
-    localList->append(123);
-
-    createBuilder(&sprite, true);
-
-    CompilerValue *v = m_builder->addConstValue(2);
-    m_builder->beginRepeatLoop(v);
-    {
-        v = m_builder->addConstValue("test");
-        m_builder->createListAppend(globalList.get(), v);
-
-        v = m_builder->addConstValue(3);
-        m_builder->beginRepeatLoop(v);
-        {
-            // Type is unknown here because a list item with unknown type is assigned later
-            v = m_builder->addListItem(localList.get(), m_builder->addConstValue(0));
-            m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
-
-            v = m_builder->addListItemIndex(localList.get(), m_builder->addConstValue(123));
-            m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
-
-            v = m_builder->addListContains(localList.get(), m_builder->addConstValue(123));
-            m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
-
-            v = m_builder->addListItem(globalList.get(), m_builder->addConstValue(0));
-            m_builder->createListReplace(localList.get(), m_builder->addConstValue(0), v);
-
-            v = m_builder->addConstValue(12.5);
-            m_builder->createListReplace(globalList.get(), m_builder->addConstValue(0), v);
-        }
-        m_builder->endLoop();
-    }
-    m_builder->endLoop();
-
-    std::string expected =
-        "123\n"
-        "0\n"
-        "1\n"
-        "0\n"
-        "-1\n"
-        "0\n"
-        "12.5\n"
-        "-1\n"
-        "0\n"
-        "12.5\n"
-        "-1\n"
-        "0\n"
-        "12.5\n"
-        "-1\n"
-        "0\n"
-        "12.5\n"
-        "-1\n"
-        "0\n";
-
-    auto code = m_builder->finalize();
-    Script script(&sprite, nullptr, nullptr);
-    script.setCode(code);
-    Thread thread(&sprite, nullptr, &script);
-    auto ctx = code->createExecutionContext(&thread);
-    testing::internal::CaptureStdout();
-    code->run(ctx.get());
-    ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
-}
-
-TEST_F(LLVMCodeBuilderTest, ListLoopTypeAnalysis11)
-{
-    Stage stage;
-    Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
-
-    auto globalList = std::make_shared<List>("", "");
-    stage.addList(globalList);
-
-    auto localList = std::make_shared<List>("", "");
-    sprite.addList(localList);
-    localList->append(123);
-    localList->append("10");
-
-    createBuilder(&sprite, true);
-
-    CompilerValue *v = m_builder->addConstValue(2);
-    m_builder->beginRepeatLoop(v);
-    {
-        v = m_builder->addConstValue("test");
-        m_builder->createListAppend(globalList.get(), v);
-
-        v = m_builder->addConstValue(3);
-        m_builder->beginRepeatLoop(v);
-        {
-            // Type is unknown here because an item from the same list is assigned later, but the list has unknown type
-            v = m_builder->addListItem(localList.get(), m_builder->addConstValue(0));
-            m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
-
-            v = m_builder->addListItemIndex(localList.get(), m_builder->addConstValue(123));
-            m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
-
-            v = m_builder->addListContains(localList.get(), m_builder->addConstValue(123));
-            m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
-
-            v = m_builder->addListItem(localList.get(), m_builder->addConstValue(1));
-            m_builder->createListReplace(localList.get(), m_builder->addConstValue(0), v);
-
-            v = m_builder->addConstValue(12.5);
-            m_builder->createListReplace(globalList.get(), m_builder->addConstValue(0), v);
-        }
-        m_builder->endLoop();
-    }
-    m_builder->endLoop();
-
-    std::string expected =
-        "123\n"
-        "0\n"
-        "1\n"
-        "10\n"
-        "-1\n"
-        "0\n"
-        "10\n"
-        "-1\n"
-        "0\n"
-        "10\n"
-        "-1\n"
-        "0\n"
-        "10\n"
-        "-1\n"
-        "0\n"
-        "10\n"
-        "-1\n"
-        "0\n";
-
-    auto code = m_builder->finalize();
-    Script script(&sprite, nullptr, nullptr);
-    script.setCode(code);
-    Thread thread(&sprite, nullptr, &script);
-    auto ctx = code->createExecutionContext(&thread);
-    testing::internal::CaptureStdout();
-    code->run(ctx.get());
-    ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
-}
-
-TEST_F(LLVMCodeBuilderTest, ListLoopTypeAnalysis12)
-{
-    Stage stage;
-    Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
-
-    auto globalList = std::make_shared<List>("", "");
-    stage.addList(globalList);
-
-    auto localList = std::make_shared<List>("", "");
-    sprite.addList(localList);
-    localList->append(123);
-
-    createBuilder(&sprite, true);
-
-    CompilerValue *v = m_builder->addConstValue(2);
-    m_builder->beginRepeatLoop(v);
-    {
-        v = m_builder->addConstValue("test");
-        m_builder->createListAppend(globalList.get(), v);
-
-        v = m_builder->addConstValue(3);
-        m_builder->beginRepeatLoop(v);
-        {
-            // Type is unknown here because an item from another list is assigned later, but it has an item from this list assigned
-            // This case is not checked because the code isn't considered valid
-            v = m_builder->addListItem(localList.get(), m_builder->addConstValue(0));
-            m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
-
-            v = m_builder->addListItemIndex(localList.get(), m_builder->addConstValue(123));
-            m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
-
-            v = m_builder->addListContains(localList.get(), m_builder->addConstValue(123));
-            m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
-
-            v = m_builder->addListItem(globalList.get(), m_builder->addConstValue(0));
-            m_builder->createListReplace(localList.get(), m_builder->addConstValue(0), v);
-
-            v = m_builder->addListItem(localList.get(), m_builder->addConstValue(0));
-            m_builder->createListReplace(globalList.get(), m_builder->addConstValue(0), v);
-        }
-        m_builder->endLoop();
-    }
-    m_builder->endLoop();
-
-    std::string expected =
-        "123\n"
-        "0\n"
-        "1\n"
-        "0\n"
-        "-1\n"
-        "0\n"
-        "0\n"
-        "-1\n"
-        "0\n"
-        "0\n"
-        "-1\n"
-        "0\n"
-        "0\n"
-        "-1\n"
-        "0\n"
-        "0\n"
-        "-1\n"
-        "0\n";
-
-    auto code = m_builder->finalize();
-    Script script(&sprite, nullptr, nullptr);
-    script.setCode(code);
-    Thread thread(&sprite, nullptr, &script);
-    auto ctx = code->createExecutionContext(&thread);
-    testing::internal::CaptureStdout();
-    code->run(ctx.get());
-    ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
-}
-
-TEST_F(LLVMCodeBuilderTest, VarAndListLoopTypeAnalysis)
-{
-    Stage stage;
-    Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
-
-    auto var = std::make_shared<Variable>("", "");
-    sprite.addVariable(var);
-
-    auto list = std::make_shared<List>("", "");
-    sprite.addList(list);
-
-    createBuilder(&sprite, true);
-
-    CompilerValue *v = m_builder->addConstValue(-2);
-    m_builder->createVariableWrite(var.get(), v);
-
-    m_builder->createListClear(list.get());
-
-    v = m_builder->addConstValue(5.25);
-    m_builder->createListAppend(list.get(), v);
-
-    v = m_builder->addConstValue(3);
-    m_builder->beginRepeatLoop(v);
-    {
-        // Type is unknown here because a variable value with unknown type is added later
-        v = m_builder->createSub(m_builder->addListSize(list.get()), m_builder->addConstValue(1));
-        v = m_builder->addListItem(list.get(), v);
-        m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
-
-        v = m_builder->addListItemIndex(list.get(), m_builder->addConstValue(5.25));
-        m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
-
-        v = m_builder->addListContains(list.get(), m_builder->addConstValue(5.25));
-        m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
-
-        v = m_builder->addVariableValue(var.get());
-        m_builder->createListAppend(list.get(), v);
-
-        v = m_builder->addConstValue("test");
-        m_builder->createVariableWrite(var.get(), v);
-    }
-    m_builder->endLoop();
-
-    std::string expected =
-        "5.25\n"
-        "0\n"
-        "1\n"
-        "-2\n"
-        "0\n"
         "1\n"
         "0\n"
         "0\n"

From 846b5f8a0a69754eeb9e6f4e24d0ee5e27e3ece4 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Fri, 1 Aug 2025 17:23:08 +0200
Subject: [PATCH 49/79] Revert "Comment out stop all test"

This reverts commit 8f183a2a364dd39df81f87b6bc1f50fd5c56afe1.
---
 test/engine/engine_test.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/test/engine/engine_test.cpp b/test/engine/engine_test.cpp
index c14fb6d4..c1dab56d 100644
--- a/test/engine/engine_test.cpp
+++ b/test/engine/engine_test.cpp
@@ -1863,7 +1863,7 @@ TEST(EngineTest, BroadcastsProject)
     ASSERT_EQ(GET_VAR(stage, "test5")->value().toString(), "2 2 0 0");
 }*/
 
-/*TEST(EngineTest, StopAll)
+TEST(EngineTest, StopAll)
 {
     Project p("stop_all.sb3");
     ASSERT_TRUE(p.load());
@@ -1877,7 +1877,7 @@ TEST(EngineTest, BroadcastsProject)
     ASSERT_VAR(stage, "i");
     ASSERT_EQ(GET_VAR(stage, "i")->value().toInt(), 11);
     ASSERT_FALSE(engine->isRunning());
-}*/
+}
 
 TEST(EngineTest, StopAllBypass)
 {

From 83f3aa571e86a1cf3e4c84c681e2ea18e3042618 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Fri, 1 Aug 2025 17:32:39 +0200
Subject: [PATCH 50/79] Uncomment more engine test cases

---
 test/engine/engine_test.cpp | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/test/engine/engine_test.cpp b/test/engine/engine_test.cpp
index c1dab56d..bb5e963e 100644
--- a/test/engine/engine_test.cpp
+++ b/test/engine/engine_test.cpp
@@ -396,7 +396,7 @@ TEST(EngineTest, Fps)
     ASSERT_EQ(engine.fps(), 250);
 }
 
-/*TEST(EngineTest, FpsProject)
+TEST(EngineTest, FpsProject)
 {
     Project p("2_frames.sb3");
     ASSERT_TRUE(p.load());
@@ -466,7 +466,7 @@ TEST(EngineTest, Fps)
     EXPECT_CALL(clock, sleep).Times(0);
     EXPECT_CALL(redrawMock, redraw());
     p.run();
-}*/
+}
 
 TEST(EngineTest, TurboModeEnabled)
 {
@@ -480,7 +480,7 @@ TEST(EngineTest, TurboModeEnabled)
     ASSERT_FALSE(engine.turboModeEnabled());
 }
 
-/*TEST(EngineTest, ExecutionOrder)
+TEST(EngineTest, ExecutionOrder)
 {
     Project p("execution_order.sb3");
     ASSERT_TRUE(p.load());
@@ -509,7 +509,7 @@ TEST(EngineTest, TurboModeEnabled)
     ASSERT_EQ(Value((*list)[10]).toString(), "Sprite1 2 msg");
     ASSERT_EQ(Value((*list)[11]).toString(), "Sprite1 3 msg");
     ASSERT_EQ(Value((*list)[12]).toString(), "Stage msg");
-}*/
+}
 
 TEST(EngineTest, KeyState)
 {
@@ -1745,7 +1745,7 @@ void questionFunction(const std::string &)
         else
             ASSERT_EQ(Value((*list)[i]).toString(), "12");
     }
-}
+}*/
 
 TEST(EngineTest, CloneLimit)
 {
@@ -1861,7 +1861,7 @@ TEST(EngineTest, BroadcastsProject)
     ASSERT_EQ(GET_VAR(stage, "test4")->value().toInt(), 10);
     ASSERT_VAR(stage, "test5");
     ASSERT_EQ(GET_VAR(stage, "test5")->value().toString(), "2 2 0 0");
-}*/
+}
 
 TEST(EngineTest, StopAll)
 {
@@ -2064,7 +2064,7 @@ TEST(EngineTest, NoRefreshWhenCallingRunningBroadcast)
     ASSERT_TRUE(GET_VAR(stage, "passed2")->value().toBool());
 }
 
-/*TEST(EngineTest, NoStopWhenCallingRunningBroadcastFromCustomBlock)
+TEST(EngineTest, NoStopWhenCallingRunningBroadcastFromCustomBlock)
 {
     // Regtest for #257
     Project p("regtest_projects/277_custom_block_call_running_broadcast_stop.sb3");
@@ -2081,7 +2081,7 @@ TEST(EngineTest, NoRefreshWhenCallingRunningBroadcast)
 
     ASSERT_VAR(stage, "passed2");
     ASSERT_TRUE(GET_VAR(stage, "passed2")->value().toBool());
-}*/
+}
 
 TEST(EngineTest, ResetRunningHats)
 {

From 096036f9420942d08cb9be476eb053c4e6f69ce3 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Sat, 2 Aug 2025 18:21:17 +0200
Subject: [PATCH 51/79] LLVMCodeBuilder: Create a global resume function in
 LLVMCompilerContext

The previous logic was incorrect because the resume function was resolved using getOrCreateFunction() and then filled with code, even if it existed.

Since it's global and can be used in the entire LLVM module, create it in LLVMCompilerContext.
---
 src/engine/internal/llvm/llvmcodebuilder.cpp  | 28 +------------
 src/engine/internal/llvm/llvmcodebuilder.h    |  2 -
 .../internal/llvm/llvmcompilercontext.cpp     | 39 +++++++++++++++++--
 .../internal/llvm/llvmcompilercontext.h       | 10 ++++-
 src/engine/internal/llvm/llvmcoroutine.cpp    | 34 ++++++++--------
 src/engine/internal/llvm/llvmcoroutine.h      |  2 +-
 6 files changed, 64 insertions(+), 51 deletions(-)

diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp
index 12043512..afb0151b 100644
--- a/src/engine/internal/llvm/llvmcodebuilder.cpp
+++ b/src/engine/internal/llvm/llvmcodebuilder.cpp
@@ -1268,8 +1268,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
                     m_builder.SetInsertPoint(suspendBranch);
                     createSuspend(coro.get(), warpArg, targetVariables);
-                    name = getResumeFunctionName(step.procedurePrototype);
-                    llvm::Value *done = m_builder.CreateCall(resolveFunction(name, m_resumeFuncType), { handle });
+                    llvm::Value *done = m_builder.CreateCall(m_ctx->coroutineResumeFunction(), { handle });
                     m_builder.CreateCondBr(done, nextBranch, suspendBranch);
 
                     m_builder.SetInsertPoint(nextBranch);
@@ -1329,24 +1328,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
     verifyFunction(m_function);
 
-    // Create resume function
-    // bool resume(void *)
-    funcName = getResumeFunctionName(m_procedurePrototype);
-    llvm::Function *resumeFunc = getOrCreateFunction(funcName, m_resumeFuncType);
-    resumeFunc->addFnAttr(llvm::Attribute::NoInline);
-    resumeFunc->addFnAttr(llvm::Attribute::OptimizeNone);
-
-    entry = llvm::BasicBlock::Create(m_llvmCtx, "entry", resumeFunc);
-    m_builder.SetInsertPoint(entry);
-
-    if (m_warp)
-        m_builder.CreateRet(m_builder.getInt1(true));
-    else
-        m_builder.CreateRet(coro->createResume(resumeFunc, resumeFunc->getArg(0)));
-
-    verifyFunction(resumeFunc);
-
-    return std::make_shared<LLVMExecutableCode>(m_ctx, m_function->getName().str(), resumeFunc->getName().str(), m_codeType);
+    return std::make_shared<LLVMExecutableCode>(m_ctx, m_function->getName().str(), m_ctx->coroutineResumeFunction()->getName().str(), m_codeType);
 }
 
 CompilerValue *LLVMCodeBuilder::addFunctionCall(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args)
@@ -1890,7 +1872,6 @@ void LLVMCodeBuilder::initTypes()
     llvm::PointerType *pointerType = llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0);
     m_valueDataType = LLVMTypes::createValueDataType(&m_builder);
     m_stringPtrType = LLVMTypes::createStringPtrType(&m_builder);
-    m_resumeFuncType = llvm::FunctionType::get(m_builder.getInt1Ty(), pointerType, false);
 }
 
 void LLVMCodeBuilder::createVariableMap()
@@ -2015,11 +1996,6 @@ std::string LLVMCodeBuilder::getMainFunctionName(BlockPrototype *procedureProtot
     return procedurePrototype ? "proc." + procedurePrototype->procCode() : name;
 }
 
-std::string LLVMCodeBuilder::getResumeFunctionName(BlockPrototype *procedurePrototype)
-{
-    return procedurePrototype ? "resume.proc." + procedurePrototype->procCode() : "resume.script";
-}
-
 llvm::FunctionType *LLVMCodeBuilder::getMainFunctionType(BlockPrototype *procedurePrototype)
 {
     // void *f(ExecutionContext *, Target *, ValueData **, List **, (warp arg), (procedure args...))
diff --git a/src/engine/internal/llvm/llvmcodebuilder.h b/src/engine/internal/llvm/llvmcodebuilder.h
index 2ddd8e98..8fc7a3c5 100644
--- a/src/engine/internal/llvm/llvmcodebuilder.h
+++ b/src/engine/internal/llvm/llvmcodebuilder.h
@@ -130,7 +130,6 @@ class LLVMCodeBuilder : public ICodeBuilder
         void popLoopScope();
 
         std::string getMainFunctionName(BlockPrototype *procedurePrototype);
-        std::string getResumeFunctionName(BlockPrototype *procedurePrototype);
         llvm::FunctionType *getMainFunctionType(BlockPrototype *procedurePrototype);
         llvm::Function *getOrCreateFunction(const std::string &name, llvm::FunctionType *type);
         void verifyFunction(llvm::Function *func);
@@ -230,7 +229,6 @@ class LLVMCodeBuilder : public ICodeBuilder
 
         llvm::StructType *m_valueDataType = nullptr;
         llvm::StructType *m_stringPtrType = nullptr;
-        llvm::FunctionType *m_resumeFuncType = nullptr;
 
         LLVMInstructionList m_instructions;
         std::vector<std::shared_ptr<LLVMRegister>> m_regs;
diff --git a/src/engine/internal/llvm/llvmcompilercontext.cpp b/src/engine/internal/llvm/llvmcompilercontext.cpp
index 74199aa1..78fc85a3 100644
--- a/src/engine/internal/llvm/llvmcompilercontext.cpp
+++ b/src/engine/internal/llvm/llvmcompilercontext.cpp
@@ -8,6 +8,7 @@
 #include <iostream>
 
 #include "llvmcompilercontext.h"
+#include "llvmcoroutine.h"
 
 using namespace libscratchcpp;
 
@@ -18,6 +19,7 @@ LLVMCompilerContext::LLVMCompilerContext(IEngine *engine, Target *target) :
     m_llvmCtxPtr(m_llvmCtx.get()),
     m_modulePtr(m_module.get()),
     m_jit((initTarget(), llvm::orc::LLJITBuilder().create())),
+    m_llvmCoroResumeFunction(createCoroResumeFunction()),
     m_llvmCoroDestroyFunction(createCoroDestroyFunction())
 {
     if (!m_jit) {
@@ -111,6 +113,11 @@ bool LLVMCompilerContext::jitInitialized() const
     return m_jitInitialized;
 }
 
+llvm::Function *LLVMCompilerContext::coroutineResumeFunction() const
+{
+    return m_llvmCoroResumeFunction;
+}
+
 void LLVMCompilerContext::destroyCoroutine(void *handle)
 {
     if (!m_jitInitialized) {
@@ -129,6 +136,26 @@ void LLVMCompilerContext::initTarget()
     llvm::InitializeNativeTargetAsmParser();
 }
 
+llvm::Function *LLVMCompilerContext::createCoroResumeFunction()
+{
+    llvm::IRBuilder<> builder(*m_llvmCtx);
+
+    // bool coro_resume(void *handle)
+    llvm::FunctionType *funcType = llvm::FunctionType::get(builder.getInt1Ty(), builder.getVoidTy()->getPointerTo(), false);
+    llvm::Function *func = llvm::Function::Create(funcType, llvm::Function::ExternalLinkage, "coro_resume", m_module.get());
+    func->setComdat(m_module->getOrInsertComdat(func->getName()));
+    func->setDSOLocal(true);
+    func->addFnAttr(llvm::Attribute::NoInline);
+    func->addFnAttr(llvm::Attribute::OptimizeNone);
+
+    llvm::BasicBlock *entry = llvm::BasicBlock::Create(*m_llvmCtx, "entry", func);
+    builder.SetInsertPoint(entry);
+    builder.CreateRet(LLVMCoroutine::createResume(m_module.get(), &builder, func, func->getArg(0)));
+
+    verifyFunction(func);
+    return func;
+}
+
 llvm::Function *LLVMCompilerContext::createCoroDestroyFunction()
 {
     llvm::IRBuilder<> builder(*m_llvmCtx);
@@ -146,10 +173,14 @@ llvm::Function *LLVMCompilerContext::createCoroDestroyFunction()
     builder.CreateCall(llvm::Intrinsic::getDeclaration(m_module.get(), llvm::Intrinsic::coro_destroy), { func->getArg(0) });
     builder.CreateRetVoid();
 
-    if (llvm::verifyFunction(*func, &llvm::errs())) {
-        llvm::errs() << "error: coro_destroy() function verficiation failed!\n";
+    verifyFunction(func);
+    return func;
+}
+
+void LLVMCompilerContext::verifyFunction(llvm::Function *function)
+{
+    if (llvm::verifyFunction(*function, &llvm::errs())) {
+        llvm::errs() << "error: " << function->getName() << "function verficiation failed!\n";
         llvm::errs() << "module name: " << m_module->getName() << "\n";
     }
-
-    return func;
 }
diff --git a/src/engine/internal/llvm/llvmcompilercontext.h b/src/engine/internal/llvm/llvmcompilercontext.h
index 27878ffe..21ae681a 100644
--- a/src/engine/internal/llvm/llvmcompilercontext.h
+++ b/src/engine/internal/llvm/llvmcompilercontext.h
@@ -28,6 +28,7 @@ class LLVMCompilerContext : public CompilerContext
         void initJit();
         bool jitInitialized() const;
 
+        llvm::Function *coroutineResumeFunction() const;
         void destroyCoroutine(void *handle);
 
         template<typename T>
@@ -44,19 +45,26 @@ class LLVMCompilerContext : public CompilerContext
         }
 
     private:
+        using ResumeCoroFuncType = bool (*)(void *);
         using DestroyCoroFuncType = void (*)(void *);
 
         void initTarget();
+        llvm::Function *createCoroResumeFunction();
         llvm::Function *createCoroDestroyFunction();
 
+        void verifyFunction(llvm::Function *function);
+
         std::unique_ptr<llvm::LLVMContext> m_llvmCtx;
         std::unique_ptr<llvm::Module> m_module;
         llvm::LLVMContext *m_llvmCtxPtr = nullptr;
         llvm::Module *m_modulePtr = nullptr;
         llvm::Expected<std::unique_ptr<llvm::orc::LLJIT>> m_jit;
+        bool m_jitInitialized = false;
+
+        llvm::Function *m_llvmCoroResumeFunction = nullptr;
+
         llvm::Function *m_llvmCoroDestroyFunction = nullptr;
         DestroyCoroFuncType m_coroDestroyFunction = nullptr;
-        bool m_jitInitialized = false;
 };
 
 } // namespace libscratchcpp
diff --git a/src/engine/internal/llvm/llvmcoroutine.cpp b/src/engine/internal/llvm/llvmcoroutine.cpp
index 97baff39..f4b268fb 100644
--- a/src/engine/internal/llvm/llvmcoroutine.cpp
+++ b/src/engine/internal/llvm/llvmcoroutine.cpp
@@ -105,32 +105,32 @@ void LLVMCoroutine::createSuspend()
     m_builder->SetInsertPoint(resumeBranch);
 }
 
-llvm::Value *LLVMCoroutine::createResume(llvm::Function *function, llvm::Value *coroHandle)
+llvm::Value *LLVMCoroutine::createResume(llvm::Module *module, llvm::IRBuilder<> *builder, llvm::Function *function, llvm::Value *coroHandle)
 {
-    llvm::LLVMContext &ctx = m_builder->getContext();
-    llvm::Function *coroDone = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::coro_done);
+    llvm::LLVMContext &ctx = builder->getContext();
+    llvm::Function *coroDone = llvm::Intrinsic::getDeclaration(module, llvm::Intrinsic::coro_done);
 
-    llvm::Value *ret = m_builder->CreateAlloca(m_builder->getInt1Ty());
-    llvm::Value *done = m_builder->CreateCall(coroDone, { coroHandle });
-    done = m_builder->CreateCall(coroDone, { coroHandle });
+    llvm::Value *ret = builder->CreateAlloca(builder->getInt1Ty());
+    llvm::Value *done = builder->CreateCall(coroDone, { coroHandle });
+    done = builder->CreateCall(coroDone, { coroHandle });
 
     llvm::BasicBlock *destroyBranch = llvm::BasicBlock::Create(ctx, "", function);
     llvm::BasicBlock *resumeBranch = llvm::BasicBlock::Create(ctx, "", function);
     llvm::BasicBlock *nextBranch = llvm::BasicBlock::Create(ctx, "", function);
-    m_builder->CreateCondBr(done, destroyBranch, resumeBranch);
+    builder->CreateCondBr(done, destroyBranch, resumeBranch);
 
-    m_builder->SetInsertPoint(destroyBranch);
-    m_builder->CreateCall(llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::coro_destroy), { coroHandle });
-    m_builder->CreateBr(nextBranch);
+    builder->SetInsertPoint(destroyBranch);
+    builder->CreateCall(llvm::Intrinsic::getDeclaration(module, llvm::Intrinsic::coro_destroy), { coroHandle });
+    builder->CreateBr(nextBranch);
 
-    m_builder->SetInsertPoint(resumeBranch);
-    m_builder->CreateCall(llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::coro_resume), { coroHandle });
-    done = m_builder->CreateCall(coroDone, { coroHandle });
-    m_builder->CreateStore(done, ret);
-    m_builder->CreateCondBr(done, destroyBranch, nextBranch);
+    builder->SetInsertPoint(resumeBranch);
+    builder->CreateCall(llvm::Intrinsic::getDeclaration(module, llvm::Intrinsic::coro_resume), { coroHandle });
+    done = builder->CreateCall(coroDone, { coroHandle });
+    builder->CreateStore(done, ret);
+    builder->CreateCondBr(done, destroyBranch, nextBranch);
 
-    m_builder->SetInsertPoint(nextBranch);
-    return m_builder->CreateLoad(m_builder->getInt1Ty(), ret);
+    builder->SetInsertPoint(nextBranch);
+    return builder->CreateLoad(builder->getInt1Ty(), ret);
 }
 
 void LLVMCoroutine::end()
diff --git a/src/engine/internal/llvm/llvmcoroutine.h b/src/engine/internal/llvm/llvmcoroutine.h
index 071798d9..fa3d79fd 100644
--- a/src/engine/internal/llvm/llvmcoroutine.h
+++ b/src/engine/internal/llvm/llvmcoroutine.h
@@ -22,7 +22,7 @@ class LLVMCoroutine
         llvm::Value *didSuspendVar() const;
 
         void createSuspend();
-        llvm::Value *createResume(llvm::Function *function, llvm::Value *coroHandle);
+        static llvm::Value *createResume(llvm::Module *module, llvm::IRBuilder<> *builder, llvm::Function *function, llvm::Value *coroHandle);
         void end();
 
     private:

From cdba36717f8963c54cca6602a346f84a9dbed9c3 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Sat, 2 Aug 2025 18:21:48 +0200
Subject: [PATCH 52/79] Uncomment Clones test case

---
 test/engine/engine_test.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/test/engine/engine_test.cpp b/test/engine/engine_test.cpp
index bb5e963e..db9f54b7 100644
--- a/test/engine/engine_test.cpp
+++ b/test/engine/engine_test.cpp
@@ -1702,7 +1702,7 @@ void questionFunction(const std::string &)
 {
 }
 
-/*TEST(EngineTest, Clones)
+TEST(EngineTest, Clones)
 {
     Project p("clones.sb3");
     ASSERT_TRUE(p.load());
@@ -1745,7 +1745,7 @@ void questionFunction(const std::string &)
         else
             ASSERT_EQ(Value((*list)[i]).toString(), "12");
     }
-}*/
+}
 
 TEST(EngineTest, CloneLimit)
 {

From 8746ca813b3eced0fd50c3e4de87f372777298bc Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Sat, 2 Aug 2025 19:16:51 +0200
Subject: [PATCH 53/79] Engine: Properly handle broadcasts with the same name
 but different case

---
 src/engine/internal/engine.cpp | 43 ++++++++++++++++------------------
 1 file changed, 20 insertions(+), 23 deletions(-)

diff --git a/src/engine/internal/engine.cpp b/src/engine/internal/engine.cpp
index 98612f57..ac446a56 100644
--- a/src/engine/internal/engine.cpp
+++ b/src/engine/internal/engine.cpp
@@ -528,8 +528,8 @@ void Engine::step()
     m_frameActivity = !m_threads.empty();
 
     // Resolve stopped broadcast scripts
-    std::vector<Broadcast *> resolved;
-    std::vector<Thread *> resolvedThreads;
+    std::unordered_map<Broadcast *, Thread *> stoppedBroadcasts; // sender thread
+    std::unordered_map<Thread *, bool> runningStatus;            // sender thread
 
     for (const auto &[broadcast, senderThread] : m_broadcastSenders) {
         std::unordered_map<Broadcast *, std::vector<Script *>> *broadcastMap = nullptr;
@@ -544,44 +544,41 @@ void Engine::step()
             broadcastMap = &m_broadcastMap;
         }
 
-        bool found = false;
+        bool isRunning = false;
 
         if (broadcastMap->find(broadcast) != broadcastMap->cend()) {
             const auto &scripts = (*broadcastMap)[broadcast];
 
             for (auto script : scripts) {
                 if (std::find_if(m_threads.begin(), m_threads.end(), [script](std::shared_ptr<Thread> thread) { return thread->script() == script; }) != m_threads.end()) {
-                    found = true;
+                    isRunning = true;
                     break;
                 }
             }
         }
 
-        if (found) {
-            // If a broadcast with the same name but different case
-            // was considered stopped before, restore the promise.
-            if (std::find(resolvedThreads.begin(), resolvedThreads.end(), senderThread) != resolvedThreads.end()) {
-                senderThread->promise();
-                resolvedThreads.erase(std::remove(resolvedThreads.begin(), resolvedThreads.end(), senderThread), resolvedThreads.end());
-            }
-        } else {
-            Thread *th = senderThread;
+        if (runningStatus.find(senderThread) == runningStatus.cend() || isRunning)
+            runningStatus[senderThread] = isRunning;
 
-            if (std::find_if(m_threads.begin(), m_threads.end(), [th](std::shared_ptr<Thread> thread) { return thread.get() == th; }) != m_threads.end()) {
-                auto promise = th->promise();
+        if (!isRunning)
+            stoppedBroadcasts[broadcast] = senderThread;
+    }
 
-                if (promise)
-                    promise->resolve();
-            }
+    for (const auto &[broadcast, senderThread] : stoppedBroadcasts) {
+        m_broadcastSenders.erase(broadcast);
 
-            resolved.push_back(broadcast);
-            resolvedThreads.push_back(th);
+        // Resolve broadcast promise
+        Thread *th = senderThread;
+
+        if (std::find_if(m_threads.begin(), m_threads.end(), [th](std::shared_ptr<Thread> thread) { return thread.get() == th; }) != m_threads.end()) {
+            auto promise = th->promise().get();
+
+            // Resolve only if all broadcasts of the same name but different case are stopped
+            if (promise && !runningStatus[senderThread])
+                promise->resolve();
         }
     }
 
-    for (Broadcast *broadcast : resolved)
-        m_broadcastSenders.erase(broadcast);
-
     m_redrawRequested = false;
 
     // Step threads

From 42bd6a878f9d67cf0994a93663ca4a3450052964 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Sat, 2 Aug 2025 19:17:08 +0200
Subject: [PATCH 54/79] Uncomment all engine bug tests

---
 test/engine/engine_test.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/test/engine/engine_test.cpp b/test/engine/engine_test.cpp
index db9f54b7..cf79f594 100644
--- a/test/engine/engine_test.cpp
+++ b/test/engine/engine_test.cpp
@@ -2238,7 +2238,7 @@ TEST(EngineTest, DuplicateVariableOrListIDs)
     ASSERT_TRUE(GET_VAR(stage, "passed")->value().toBool());
 }
 
-/*TEST(EngineTest, BroadcastStopsWaitBlocks)
+TEST(EngineTest, BroadcastStopsWaitBlocks)
 {
     // Regtest for #563
     Project p("regtest_projects/563_broadcast_stops_wait_blocks.sb3");
@@ -2272,4 +2272,4 @@ TEST(EngineTest, BroadcastAndWaitCaseInsensitive)
 
     ASSERT_VAR(stage, "passed");
     ASSERT_TRUE(GET_VAR(stage, "passed")->value().toBool());
-}*/
+}

From 9b7ae5a37dc15c79da51a6ff209758aad6e2b3c5 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Sun, 3 Aug 2025 10:12:56 +0200
Subject: [PATCH 55/79] Store raw data pointer in List

---
 include/scratchcpp/list.h                    | 11 ++++++++++-
 src/scratch/list_functions.cpp               |  5 +++++
 src/scratch/list_functions.h                 |  1 +
 test/scratch_classes/list_functions_test.cpp | 13 +++++++++++++
 test/scratch_classes/list_test.cpp           | 17 +++++++++++++++++
 5 files changed, 46 insertions(+), 1 deletion(-)

diff --git a/include/scratchcpp/list.h b/include/scratchcpp/list.h
index 9d5e4b68..47c6782c 100644
--- a/include/scratchcpp/list.h
+++ b/include/scratchcpp/list.h
@@ -41,7 +41,13 @@ class LIBSCRATCHCPP_EXPORT List : public Entity
         void setMonitor(Monitor *monitor);
 
         /*! Returns a pointer to the raw list data. */
-        inline ValueData *data() const { return m_dataPtr->data(); }
+        inline ValueData *data() const { return m_rawDataPtr; }
+
+        /*!
+         * Returns a pointer to pointer to the raw list data.
+         * \note This is used internally by compiled code for various optimizations.
+         */
+        inline ValueData *const *dataPtr() const { return &m_rawDataPtr; }
 
         /*!
          * Returns a pointer to the list size.
@@ -247,6 +253,8 @@ class LIBSCRATCHCPP_EXPORT List : public Entity
                 value_free(&m_dataPtr->back());
                 m_dataPtr->erase(m_dataPtr->end());
             }
+
+            m_rawDataPtr = m_dataPtr->data();
         }
 
         inline size_t getAllocSize(size_t x)
@@ -264,6 +272,7 @@ class LIBSCRATCHCPP_EXPORT List : public Entity
 
         spimpl::unique_impl_ptr<ListPrivate> impl;
         veque::veque<ValueData> *m_dataPtr = nullptr; // NOTE: accessing through pointer is faster! (from benchmarks)
+        ValueData *m_rawDataPtr = nullptr;
         size_t m_size = 0;
 };
 
diff --git a/src/scratch/list_functions.cpp b/src/scratch/list_functions.cpp
index 948e3e10..5ef5e681 100644
--- a/src/scratch/list_functions.cpp
+++ b/src/scratch/list_functions.cpp
@@ -38,6 +38,11 @@ extern "C"
         return list->data();
     }
 
+    ValueData *const *list_data_ptr(List *list)
+    {
+        return list->dataPtr();
+    }
+
     size_t *list_size_ptr(List *list)
     {
         return list->sizePtr();
diff --git a/src/scratch/list_functions.h b/src/scratch/list_functions.h
index 7080281c..f6837419 100644
--- a/src/scratch/list_functions.h
+++ b/src/scratch/list_functions.h
@@ -21,6 +21,7 @@ extern "C"
 
     ValueData *list_get_item(List *list, size_t index);
     ValueData *list_data(List *list);
+    ValueData *const *list_data_ptr(List *list);
     size_t *list_size_ptr(List *list);
     const size_t *list_alloc_size_ptr(List *list);
     size_t list_size(List *list);
diff --git a/test/scratch_classes/list_functions_test.cpp b/test/scratch_classes/list_functions_test.cpp
index 0aeaf48e..898757b7 100644
--- a/test/scratch_classes/list_functions_test.cpp
+++ b/test/scratch_classes/list_functions_test.cpp
@@ -100,6 +100,19 @@ TEST(ListFunctionsTest, Data)
     ASSERT_EQ(data, list.data());
 }
 
+TEST(ListFunctionsTest, DataPtr)
+{
+    List list("", "");
+    list.append("Lorem");
+    list.append("ipsum");
+    list.append("dolor");
+    list.append("sit");
+    list.append("amet");
+
+    ValueData *const *dataPtr = list_data_ptr(&list);
+    ASSERT_EQ(dataPtr, list.dataPtr());
+}
+
 TEST(ListFunctionsTest, SizePtr)
 {
     List list("", "");
diff --git a/test/scratch_classes/list_test.cpp b/test/scratch_classes/list_test.cpp
index 5aa4d1c2..257b8778 100644
--- a/test/scratch_classes/list_test.cpp
+++ b/test/scratch_classes/list_test.cpp
@@ -58,6 +58,23 @@ TEST(ListTest, Data)
     ASSERT_EQ(&data[4], &list[4]);
 }
 
+TEST(ListTest, DataPtr)
+{
+    List list("", "");
+    list.append("Lorem");
+    list.append("ipsum");
+    list.append("dolor");
+    list.append("sit");
+    list.append("amet");
+
+    ValueData *data = *list.dataPtr();
+    ASSERT_EQ(&data[0], &list[0]);
+    ASSERT_EQ(&data[1], &list[1]);
+    ASSERT_EQ(&data[2], &list[2]);
+    ASSERT_EQ(&data[3], &list[3]);
+    ASSERT_EQ(&data[4], &list[4]);
+}
+
 TEST(ListTest, SizePtr)
 {
     List list("", "test list");

From fb7ad85dd4dd596c01a8134e7bcd9d5c82082742 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Sun, 3 Aug 2025 10:24:51 +0200
Subject: [PATCH 56/79] LLVMCodeBuilder: Use pointer to list data pointer

Avoid unnecessary function call to list_data().
---
 src/engine/internal/llvm/llvmcodebuilder.cpp | 53 ++++----------------
 src/engine/internal/llvm/llvmcodebuilder.h   |  5 +-
 src/engine/internal/llvm/llvmlistptr.h       |  1 -
 3 files changed, 12 insertions(+), 47 deletions(-)

diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp
index afb0151b..d6e246db 100644
--- a/src/engine/internal/llvm/llvmcodebuilder.cpp
+++ b/src/engine/internal/llvm/llvmcodebuilder.cpp
@@ -139,14 +139,11 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
     for (auto &[list, listPtr] : m_listPtrs) {
         listPtr.ptr = getListPtr(targetLists, list);
 
-        listPtr.dataPtr = m_builder.CreateAlloca(m_valueDataType->getPointerTo());
-        m_builder.CreateStore(m_builder.CreateCall(resolve_list_data(), listPtr.ptr), listPtr.dataPtr);
+        listPtr.dataPtr = m_builder.CreateAlloca(m_valueDataType->getPointerTo()->getPointerTo());
+        m_builder.CreateStore(m_builder.CreateCall(resolve_list_data_ptr(), listPtr.ptr), listPtr.dataPtr);
 
         listPtr.sizePtr = m_builder.CreateCall(resolve_list_size_ptr(), listPtr.ptr);
         listPtr.allocatedSizePtr = m_builder.CreateCall(resolve_list_alloc_size_ptr(), listPtr.ptr);
-
-        listPtr.dataPtrDirty = m_builder.CreateAlloca(m_builder.getInt1Ty());
-        m_builder.CreateStore(m_builder.getInt1(false), listPtr.dataPtrDirty);
     }
 
     assert(m_loopScope == -1);
@@ -790,13 +787,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
             case LLVMInstruction::Type::ClearList: {
                 assert(step.args.size() == 0);
                 LLVMListPtr &listPtr = m_listPtrs[step.workList];
-                llvm::Value *oldAllocatedSize = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.allocatedSizePtr);
                 m_builder.CreateCall(resolve_list_clear(), listPtr.ptr);
-
-                // Clearing may deallocate, so check if the allocated size changed
-                llvm::Value *dataPtrDirty = m_builder.CreateLoad(m_builder.getInt1Ty(), listPtr.dataPtrDirty);
-                llvm::Value *allocatedSize = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.allocatedSizePtr);
-                m_builder.CreateStore(m_builder.CreateOr(dataPtrDirty, m_builder.CreateICmpNE(allocatedSize, oldAllocatedSize)), listPtr.dataPtrDirty);
                 break;
             }
 
@@ -819,7 +810,6 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 m_builder.SetInsertPoint(removeBlock);
                 index = m_builder.CreateFPToUI(castValue(arg.second, arg.first), m_builder.getInt64Ty());
                 m_builder.CreateCall(resolve_list_remove(), { listPtr.ptr, index });
-                // NOTE: Removing doesn't deallocate (see List::removeAt()), so there's no need to update the data pointer
                 m_builder.CreateBr(nextBlock);
 
                 m_builder.SetInsertPoint(nextBlock);
@@ -857,7 +847,6 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 m_builder.SetInsertPoint(elseBlock);
                 itemPtr = m_builder.CreateCall(resolve_list_append_empty(), listPtr.ptr);
                 createReusedValueStore(arg.second, itemPtr, type, listType);
-                m_builder.CreateStore(m_builder.getInt1(true), listPtr.dataPtrDirty);
                 m_builder.CreateBr(nextBlock);
 
                 m_builder.SetInsertPoint(nextBlock);
@@ -877,8 +866,6 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 if (m_warp)
                     listType = m_typeAnalyzer.listType(step.workList, &step, Compiler::StaticType::Unknown, false);
 
-                llvm::Value *oldAllocatedSize = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.allocatedSizePtr);
-
                 // Range check
                 llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.sizePtr);
                 llvm::Value *min = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0));
@@ -895,11 +882,6 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Value *itemPtr = m_builder.CreateCall(resolve_list_insert_empty(), { listPtr.ptr, index });
                 createReusedValueStore(valueArg.second, itemPtr, type, listType);
 
-                // Check if the allocated size changed
-                llvm::Value *dataPtrDirty = m_builder.CreateLoad(m_builder.getInt1Ty(), listPtr.dataPtrDirty);
-                llvm::Value *allocatedSize = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.allocatedSizePtr);
-                m_builder.CreateStore(m_builder.CreateOr(dataPtrDirty, m_builder.CreateICmpNE(allocatedSize, oldAllocatedSize)), listPtr.dataPtrDirty);
-
                 m_builder.CreateBr(nextBlock);
 
                 m_builder.SetInsertPoint(nextBlock);
@@ -1275,7 +1257,6 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 }
 
                 reloadVariables(targetVariables);
-                reloadLists();
                 break;
             }
 
@@ -2384,6 +2365,11 @@ llvm::Value *LLVMCodeBuilder::getListPtr(llvm::Value *targetLists, List *list)
     return m_builder.CreateIntToPtr(addr, m_valueDataType->getPointerTo());
 }
 
+llvm::Value *LLVMCodeBuilder::getListDataPtr(const LLVMListPtr &listPtr)
+{
+    return m_builder.CreateLoad(m_valueDataType->getPointerTo(), m_builder.CreateLoad(m_valueDataType->getPointerTo()->getPointerTo(), listPtr.dataPtr));
+}
+
 void LLVMCodeBuilder::syncVariables(llvm::Value *targetVariables)
 {
     // Copy stack variables to the actual variables
@@ -2404,23 +2390,6 @@ void LLVMCodeBuilder::reloadVariables(llvm::Value *targetVariables)
     }
 }
 
-void LLVMCodeBuilder::reloadLists()
-{
-    // Reset list data dirty
-    for (auto &[list, listPtr] : m_listPtrs)
-        m_builder.CreateStore(m_builder.getInt1(true), listPtr.dataPtrDirty);
-}
-
-void LLVMCodeBuilder::updateListDataPtr(const LLVMListPtr &listPtr)
-{
-    // dataPtr = dirty ? list_data(list) : dataPtr
-    // dirty = false
-    llvm::Value *dirty = m_builder.CreateLoad(m_builder.getInt1Ty(), listPtr.dataPtrDirty);
-    llvm::Value *dataPtr = m_builder.CreateSelect(dirty, m_builder.CreateCall(resolve_list_data(), listPtr.ptr), m_builder.CreateLoad(m_valueDataType->getPointerTo(), listPtr.dataPtr));
-    m_builder.CreateStore(dataPtr, listPtr.dataPtr);
-    m_builder.CreateStore(m_builder.getInt1(false), listPtr.dataPtrDirty);
-}
-
 LLVMRegister *LLVMCodeBuilder::createOp(LLVMInstruction::Type type, Compiler::StaticType retType, Compiler::StaticType argType, const Compiler::Args &args)
 {
     return createOp({ type, currentLoopScope(), m_loopCondition }, retType, argType, args);
@@ -2573,8 +2542,7 @@ void LLVMCodeBuilder::copyStructField(llvm::Value *source, llvm::Value *target,
 
 llvm::Value *LLVMCodeBuilder::getListItem(const LLVMListPtr &listPtr, llvm::Value *index)
 {
-    updateListDataPtr(listPtr);
-    return m_builder.CreateGEP(m_valueDataType, m_builder.CreateLoad(m_valueDataType->getPointerTo(), listPtr.dataPtr), index);
+    return m_builder.CreateGEP(m_valueDataType, getListDataPtr(listPtr), index);
 }
 
 llvm::Value *LLVMCodeBuilder::getListItemIndex(const LLVMListPtr &listPtr, Compiler::StaticType listType, LLVMRegister *item)
@@ -2932,7 +2900,6 @@ void LLVMCodeBuilder::createSuspend(LLVMCoroutine *coro, llvm::Value *warpArg, l
         syncVariables(targetVariables);
         coro->createSuspend();
         reloadVariables(targetVariables);
-        reloadLists();
 
         if (warpArg) {
             m_builder.CreateBr(nextBranch);
@@ -3090,10 +3057,10 @@ llvm::FunctionCallee LLVMCodeBuilder::resolve_list_insert_empty()
     return resolveFunction("list_insert_empty", llvm::FunctionType::get(m_valueDataType->getPointerTo(), { listPtr, m_builder.getInt64Ty() }, false));
 }
 
-llvm::FunctionCallee LLVMCodeBuilder::resolve_list_data()
+llvm::FunctionCallee LLVMCodeBuilder::resolve_list_data_ptr()
 {
     llvm::Type *listPtr = llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0);
-    llvm::FunctionCallee callee = resolveFunction("list_data", llvm::FunctionType::get(m_valueDataType->getPointerTo(), { listPtr }, false));
+    llvm::FunctionCallee callee = resolveFunction("list_data_ptr", llvm::FunctionType::get(m_valueDataType->getPointerTo()->getPointerTo(), { listPtr }, false));
     llvm::Function *func = llvm::cast<llvm::Function>(callee.getCallee());
     func->addFnAttr(llvm::Attribute::ReadOnly);
     return callee;
diff --git a/src/engine/internal/llvm/llvmcodebuilder.h b/src/engine/internal/llvm/llvmcodebuilder.h
index 8fc7a3c5..ab641240 100644
--- a/src/engine/internal/llvm/llvmcodebuilder.h
+++ b/src/engine/internal/llvm/llvmcodebuilder.h
@@ -150,10 +150,9 @@ class LLVMCodeBuilder : public ICodeBuilder
 
         llvm::Value *getVariablePtr(llvm::Value *targetVariables, Variable *variable);
         llvm::Value *getListPtr(llvm::Value *targetLists, List *list);
+        llvm::Value *getListDataPtr(const LLVMListPtr &listPtr);
         void syncVariables(llvm::Value *targetVariables);
         void reloadVariables(llvm::Value *targetVariables);
-        void reloadLists();
-        void updateListDataPtr(const LLVMListPtr &listPtr);
 
         LLVMRegister *createOp(LLVMInstruction::Type type, Compiler::StaticType retType, Compiler::StaticType argType, const Compiler::Args &args);
         LLVMRegister *createOp(LLVMInstruction::Type type, Compiler::StaticType retType, const Compiler::ArgTypes &argTypes = {}, const Compiler::Args &args = {});
@@ -197,7 +196,7 @@ class LLVMCodeBuilder : public ICodeBuilder
         llvm::FunctionCallee resolve_list_remove();
         llvm::FunctionCallee resolve_list_append_empty();
         llvm::FunctionCallee resolve_list_insert_empty();
-        llvm::FunctionCallee resolve_list_data();
+        llvm::FunctionCallee resolve_list_data_ptr();
         llvm::FunctionCallee resolve_list_size_ptr();
         llvm::FunctionCallee resolve_list_alloc_size_ptr();
         llvm::FunctionCallee resolve_list_to_string();
diff --git a/src/engine/internal/llvm/llvmlistptr.h b/src/engine/internal/llvm/llvmlistptr.h
index 52e4aff5..7b13bc39 100644
--- a/src/engine/internal/llvm/llvmlistptr.h
+++ b/src/engine/internal/llvm/llvmlistptr.h
@@ -24,7 +24,6 @@ struct LLVMListPtr
         llvm::Value *dataPtr = nullptr;
         llvm::Value *sizePtr = nullptr;
         llvm::Value *allocatedSizePtr = nullptr;
-        llvm::Value *dataPtrDirty = nullptr;
 
         // Used in build phase to check the type safety of lists in loops
         std::unordered_map<LLVMLoopScope *, std::vector<LLVMInstruction *>> loopListWrites; // loop scope, write instructions

From 26a5c6318f0c77b3f949fb8ac0c097d1aa3986dd Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Sun, 3 Aug 2025 14:44:58 +0200
Subject: [PATCH 57/79] Add LLVMTestUtils class

---
 test/llvm/CMakeLists.txt    |   2 +
 test/llvm/llvmtestutils.cpp | 322 ++++++++++++++++++++++++++++++++++++
 test/llvm/llvmtestutils.h   |  95 +++++++++++
 3 files changed, 419 insertions(+)
 create mode 100644 test/llvm/llvmtestutils.cpp
 create mode 100644 test/llvm/llvmtestutils.h

diff --git a/test/llvm/CMakeLists.txt b/test/llvm/CMakeLists.txt
index e5bd2c39..9db31dd6 100644
--- a/test/llvm/CMakeLists.txt
+++ b/test/llvm/CMakeLists.txt
@@ -16,6 +16,8 @@ target_link_libraries(
 add_executable(
   llvm_test
   main.cpp
+  llvmtestutils.cpp
+  llvmtestutils.h
   llvmexecutioncontext_test.cpp
   llvmexecutablecode_test.cpp
   llvmcodebuilder_test.cpp
diff --git a/test/llvm/llvmtestutils.cpp b/test/llvm/llvmtestutils.cpp
new file mode 100644
index 00000000..2ace9069
--- /dev/null
+++ b/test/llvm/llvmtestutils.cpp
@@ -0,0 +1,322 @@
+#include <scratchcpp/compilerconstant.h>
+#include <scratchcpp/executablecode.h>
+#include <scratchcpp/executioncontext.h>
+#include <scratchcpp/script.h>
+#include <scratchcpp/thread.h>
+#include <scratchcpp/string_functions.h>
+#include <scratchcpp/string_pool.h>
+#include <scratchcpp/stringptr.h>
+#include <engine/internal/llvm/llvmcodebuilder.h>
+#include <engine/internal/llvm/llvmcompilercontext.h>
+
+#include "llvmtestutils.h"
+#include "testfunctions.h"
+
+using namespace libscratchcpp;
+
+LLVMTestUtils::LLVMTestUtils()
+{
+    test_function(nullptr, nullptr, nullptr, nullptr, nullptr); // force dependency
+}
+
+LLVMCodeBuilder *LLVMTestUtils::createBuilder(Target *target, BlockPrototype *procedurePrototype, Compiler::CodeType codeType)
+{
+    if (m_contexts.find(target) == m_contexts.cend() || !target)
+        m_contexts[target] = std::make_shared<LLVMCompilerContext>(&m_engine, target);
+
+    m_contextList.push_back(m_contexts[target]);
+    m_builder = std::make_shared<LLVMCodeBuilder>(m_contexts[target].get(), procedurePrototype, codeType);
+
+    return m_builder.get();
+}
+
+LLVMCodeBuilder *LLVMTestUtils::createBuilder(Target *target, bool warp)
+{
+    m_procedurePrototype = std::make_shared<BlockPrototype>("test");
+    m_procedurePrototype->setWarp(warp);
+    createBuilder(target, m_procedurePrototype.get());
+
+    return m_builder.get();
+}
+
+LLVMCodeBuilder *LLVMTestUtils::createBuilder(bool warp)
+{
+    return createBuilder(nullptr, warp);
+}
+
+LLVMCodeBuilder *LLVMTestUtils::createReporterBuilder(Target *target)
+{
+    return createBuilder(target, nullptr, Compiler::CodeType::Reporter);
+}
+
+LLVMCodeBuilder *LLVMTestUtils::createPredicateBuilder(Target *target)
+{
+    return createBuilder(target, nullptr, Compiler::CodeType::HatPredicate);
+}
+
+CompilerValue *LLVMTestUtils::callConstFuncForType(ValueType type, CompilerValue *arg)
+{
+    switch (type) {
+        case ValueType::Number:
+            return m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }, { arg });
+
+        case ValueType::Bool:
+            return m_builder->addFunctionCall("test_const_bool", Compiler::StaticType::Bool, { Compiler::StaticType::Bool }, { arg });
+
+        case ValueType::String:
+            return m_builder->addFunctionCall("test_const_string", Compiler::StaticType::String, { Compiler::StaticType::String }, { arg });
+
+        default:
+            EXPECT_TRUE(false);
+            return nullptr;
+    }
+}
+
+Value LLVMTestUtils::getOpResult(OpType type, bool rawArg, const Value &v)
+{
+    createReporterBuilder(nullptr);
+
+    CompilerValue *arg = m_builder->addConstValue(v);
+
+    if (rawArg)
+        addOp(type, arg);
+    else {
+        arg = callConstFuncForType(v.type(), arg);
+        addOp(type, arg);
+    }
+
+    auto code = m_builder->finalize();
+    Script script(&m_target, nullptr, nullptr);
+    script.setCode(code);
+    Thread thread(&m_target, nullptr, &script);
+    auto ctx = code->createExecutionContext(&thread);
+
+    ValueData data = code->runReporter(ctx.get());
+    Value ret(data);
+    value_free(&data);
+
+    return ret;
+}
+
+Value LLVMTestUtils::getOpResult(OpType type, bool rawArgs, const Value &v1, const Value &v2)
+{
+    createReporterBuilder(nullptr);
+
+    CompilerValue *arg1 = m_builder->addConstValue(v1);
+    CompilerValue *arg2 = m_builder->addConstValue(v2);
+
+    if (rawArgs)
+        addOp(type, arg1, arg2);
+    else {
+        arg1 = callConstFuncForType(v1.type(), arg1);
+        arg2 = callConstFuncForType(v2.type(), arg2);
+        addOp(type, arg1, arg2);
+    }
+
+    auto code = m_builder->finalize();
+    Script script(&m_target, nullptr, nullptr);
+    script.setCode(code);
+    Thread thread(&m_target, nullptr, &script);
+    auto ctx = code->createExecutionContext(&thread);
+    ctx->setRng(&m_rng);
+
+    ValueData data = code->runReporter(ctx.get());
+    Value ret(data);
+    value_free(&data);
+
+    return ret;
+}
+
+Value LLVMTestUtils::getExpectedOpResult(OpType type, const Value &v)
+{
+    switch (type) {
+        case OpType::Not:
+            return !v.toBool();
+
+        case OpType::StringLength:
+            return v.toUtf16().size();
+
+        default:
+            EXPECT_TRUE(false);
+            return Value();
+    }
+}
+
+Value LLVMTestUtils::getExpectedOpResult(OpType type, const Value &v1, const Value &v2)
+{
+    switch (type) {
+        case OpType::Add:
+            return v1 + v2;
+
+        case OpType::Sub:
+            return v1 - v2;
+
+        case OpType::Mul:
+            return v1 * v2;
+
+        case OpType::Div:
+            return v1 / v2;
+
+        case OpType::Random: {
+            const double sum = v1.toDouble() + v2.toDouble();
+
+            if (std::isnan(sum) || std::isinf(sum))
+                return sum;
+
+            return v1.isInt() && v2.isInt() ? m_rng.randint(v1.toLong(), v2.toLong()) : m_rng.randintDouble(v1.toDouble(), v2.toDouble());
+        }
+
+        case OpType::RandomInt:
+            return m_rng.randint(v1.toLong(), v2.toLong());
+
+        case OpType::CmpEQ:
+            return v1 == v2;
+
+        case OpType::CmpGT:
+            return v1 > v2;
+
+        case OpType::CmpLT:
+            return v1 < v2;
+
+        case OpType::StrCmpEQCS:
+            return string_compare_case_sensitive(value_toStringPtr(&v1.data()), value_toStringPtr(&v2.data())) == 0;
+
+        case OpType::StrCmpEQCI:
+            return string_compare_case_insensitive(value_toStringPtr(&v1.data()), value_toStringPtr(&v2.data())) == 0;
+
+        case OpType::And:
+            return v1.toBool() && v2.toBool();
+
+        case OpType::Or:
+            return v1.toBool() || v2.toBool();
+
+        case OpType::Mod:
+            return v1 % v2;
+
+        default:
+            EXPECT_TRUE(false);
+            return Value();
+    }
+}
+
+const RandomGeneratorMock &LLVMTestUtils::rng() const
+{
+    return m_rng;
+}
+
+CompilerValue *LLVMTestUtils::addOp(OpType type, CompilerValue *arg)
+{
+    switch (type) {
+        case OpType::Not:
+            return m_builder->createNot(arg);
+
+        case OpType::Round:
+            return m_builder->createRound(arg);
+
+        case OpType::Abs:
+            return m_builder->createAbs(arg);
+
+        case OpType::Floor:
+            return m_builder->createFloor(arg);
+
+        case OpType::Ceil:
+            return m_builder->createCeil(arg);
+
+        case OpType::Sqrt:
+            return m_builder->createSqrt(arg);
+
+        case OpType::Sin:
+            return m_builder->createSin(arg);
+
+        case OpType::Cos:
+            return m_builder->createCos(arg);
+
+        case OpType::Tan:
+            return m_builder->createTan(arg);
+
+        case OpType::Asin:
+            return m_builder->createAsin(arg);
+
+        case OpType::Acos:
+            return m_builder->createAcos(arg);
+
+        case OpType::Atan:
+            return m_builder->createAtan(arg);
+
+        case OpType::Ln:
+            return m_builder->createLn(arg);
+
+        case OpType::Log10:
+            return m_builder->createLog10(arg);
+
+        case OpType::Exp:
+            return m_builder->createExp(arg);
+
+        case OpType::Exp10:
+            return m_builder->createExp10(arg);
+
+        case OpType::StringLength:
+            return m_builder->addStringLength(arg);
+
+        default:
+            EXPECT_TRUE(false);
+            return nullptr;
+    }
+}
+
+CompilerValue *LLVMTestUtils::addOp(OpType type, CompilerValue *arg1, CompilerValue *arg2)
+{
+    switch (type) {
+        case OpType::Add:
+            return m_builder->createAdd(arg1, arg2);
+
+        case OpType::Sub:
+            return m_builder->createSub(arg1, arg2);
+
+        case OpType::Mul:
+            return m_builder->createMul(arg1, arg2);
+
+        case OpType::Div:
+            return m_builder->createDiv(arg1, arg2);
+
+        case OpType::Random:
+            return m_builder->createRandom(arg1, arg2);
+
+        case OpType::RandomInt:
+            return m_builder->createRandomInt(arg1, arg2);
+
+        case OpType::CmpEQ:
+            return m_builder->createCmpEQ(arg1, arg2);
+
+        case OpType::CmpGT:
+            return m_builder->createCmpGT(arg1, arg2);
+
+        case OpType::CmpLT:
+            return m_builder->createCmpLT(arg1, arg2);
+
+        case OpType::StrCmpEQCS:
+            return m_builder->createStrCmpEQ(arg1, arg2, true);
+
+        case OpType::StrCmpEQCI:
+            return m_builder->createStrCmpEQ(arg1, arg2, false);
+
+        case OpType::And:
+            return m_builder->createAnd(arg1, arg2);
+
+        case OpType::Or:
+            return m_builder->createOr(arg1, arg2);
+
+        case OpType::Mod:
+            return m_builder->createMod(arg1, arg2);
+
+        case OpType::StringConcat:
+            return m_builder->createStringConcat(arg1, arg2);
+
+        case OpType::StringChar:
+            return m_builder->addStringChar(arg1, arg2);
+
+        default:
+            EXPECT_TRUE(false);
+            return nullptr;
+    }
+}
diff --git a/test/llvm/llvmtestutils.h b/test/llvm/llvmtestutils.h
new file mode 100644
index 00000000..8d864fcf
--- /dev/null
+++ b/test/llvm/llvmtestutils.h
@@ -0,0 +1,95 @@
+#pragma once
+
+#include <scratchcpp/compiler.h>
+#include <enginemock.h>
+#include <targetmock.h>
+#include <randomgeneratormock.h>
+
+#define ASSERT_NUM_OP1(utils, type, rawArg, v) ASSERT_EQ(utils.getOpResult(type, rawArg, v).toDouble(), m_utils.getExpectedOpResult(type, v).toDouble());
+#define ASSERT_NUM_OP2(utils, type, rawArgs, v1, v2) ASSERT_EQ(utils.getOpResult(type, rawArgs, v1, v2).toDouble(), m_utils.getExpectedOpResult(type, v1, v2).toDouble());
+
+#define ASSERT_BOOL_OP1(utils, type, rawArg, v) ASSERT_EQ(utils.getOpResult(type, rawArg, v).toBool(), m_utils.getExpectedOpResult(type, v).toBool());
+#define ASSERT_BOOL_OP2(utils, type, rawArgs, v1, v2) ASSERT_EQ(utils.getOpResult(type, rawArgs, v1, v2).toBool(), m_utils.getExpectedOpResult(type, v1, v2).toBool());
+
+#define ASSERT_STRING_OP1(utils, type, rawArg, v) ASSERT_EQ(utils.getOpResult(type, rawArg, v).toString(), m_utils.getExpectedOpResult(type, v).toString());
+#define ASSERT_STRING_OP2(utils, type, rawArgs, v1, v2) ASSERT_EQ(utils.getOpResult(type, rawArgs, v1, v2).toString(), m_utils.getExpectedOpResult(type, v1, v2).toString());
+
+namespace libscratchcpp
+{
+
+class LLVMCompilerContext;
+class LLVMCodeBuilder;
+
+class LLVMTestUtils
+{
+    public:
+        enum class OpType
+        {
+            Add,
+            Sub,
+            Mul,
+            Div,
+            Random,
+            RandomInt,
+            CmpEQ,
+            CmpGT,
+            CmpLT,
+            StrCmpEQCS,
+            StrCmpEQCI,
+            And,
+            Or,
+            Not,
+            Mod,
+            Round,
+            Abs,
+            Floor,
+            Ceil,
+            Sqrt,
+            Sin,
+            Cos,
+            Tan,
+            Asin,
+            Acos,
+            Atan,
+            Ln,
+            Log10,
+            Exp,
+            Exp10,
+            StringConcat,
+            StringChar,
+            StringLength
+        };
+
+        LLVMTestUtils();
+
+        LLVMCodeBuilder *createBuilder(Target *target, BlockPrototype *procedurePrototype, Compiler::CodeType codeType = Compiler::CodeType::Script);
+        LLVMCodeBuilder *createBuilder(Target *target, bool warp);
+        LLVMCodeBuilder *createBuilder(bool warp);
+
+        LLVMCodeBuilder *createReporterBuilder(Target *target);
+        LLVMCodeBuilder *createPredicateBuilder(Target *target);
+
+        CompilerValue *callConstFuncForType(ValueType type, CompilerValue *arg);
+
+        Value getOpResult(OpType type, bool rawArg, const Value &v);
+        Value getOpResult(OpType type, bool rawArgs, const Value &v1, const Value &v2);
+
+        Value getExpectedOpResult(OpType type, const Value &v);
+        Value getExpectedOpResult(OpType type, const Value &v1, const Value &v2);
+
+        const RandomGeneratorMock &rng() const;
+
+    private:
+        CompilerValue *addOp(OpType type, CompilerValue *arg);
+        CompilerValue *addOp(OpType type, CompilerValue *arg1, CompilerValue *arg2);
+
+        std::unordered_map<Target *, std::shared_ptr<LLVMCompilerContext>> m_contexts;
+        std::vector<std::shared_ptr<LLVMCompilerContext>> m_contextList;
+        std::shared_ptr<LLVMCodeBuilder> m_builder;
+        std::shared_ptr<BlockPrototype> m_procedurePrototype;
+        EngineMock m_engine;
+        TargetMock m_target; // NOTE: isStage() is used for call expectations
+        RandomGeneratorMock m_rng;
+};
+
+} // namespace libscratchcpp

From e70709f9b90893caa93e08bd7e4f9ca8baa990cd Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Sun, 3 Aug 2025 14:59:24 +0200
Subject: [PATCH 58/79] LLVMCodeBuilder: Move operator tests to separate test
 suites

---
 test/llvm/CMakeLists.txt                      |   33 +
 test/llvm/llvmcodebuilder_test.cpp            | 1496 -----------------
 test/llvm/operators/equal_comparison_test.cpp | 1205 +++++++++++++
 test/llvm/operators/greater_than_test.cpp     | 1340 +++++++++++++++
 test/llvm/operators/less_than_test.cpp        | 1340 +++++++++++++++
 test/llvm/operators/logic/and_test.cpp        |  890 ++++++++++
 test/llvm/operators/logic/not_test.cpp        |  260 +++
 test/llvm/operators/logic/or_test.cpp         |  890 ++++++++++
 test/llvm/operators/math/abs_test.cpp         |  116 ++
 test/llvm/operators/math/acos_test.cpp        |  126 ++
 test/llvm/operators/math/add_test.cpp         |  130 ++
 test/llvm/operators/math/asin_test.cpp        |  126 ++
 test/llvm/operators/math/atan_test.cpp        |   86 +
 test/llvm/operators/math/ceil_test.cpp        |  176 ++
 test/llvm/operators/math/cos_test.cpp         |  136 ++
 test/llvm/operators/math/divide_test.cpp      |  270 +++
 test/llvm/operators/math/exp10_test.cpp       |  106 ++
 test/llvm/operators/math/exp_test.cpp         |   96 ++
 test/llvm/operators/math/floor_test.cpp       |  166 ++
 test/llvm/operators/math/ln_test.cpp          |  122 ++
 test/llvm/operators/math/log10_test.cpp       |  112 ++
 test/llvm/operators/math/mod_test.cpp         |  280 +++
 test/llvm/operators/math/multiply_test.cpp    |  180 ++
 test/llvm/operators/math/random_int_test.cpp  |  134 ++
 test/llvm/operators/math/random_test.cpp      |  444 +++++
 test/llvm/operators/math/round_test.cpp       |  146 ++
 test/llvm/operators/math/sin_test.cpp         |  136 ++
 test/llvm/operators/math/sqrt_test.cpp        |   96 ++
 test/llvm/operators/math/subtract_test.cpp    |  130 ++
 test/llvm/operators/math/tan_test.cpp         |  188 +++
 .../operators/string/string_char_test.cpp     |   80 +
 .../operators/string/string_concat_test.cpp   |   40 +
 .../string_equal_case_insensitive_test.cpp    | 1210 +++++++++++++
 .../string_equal_case_sensitive_test.cpp      | 1210 +++++++++++++
 .../operators/string/string_length_test.cpp   |   50 +
 35 files changed, 12050 insertions(+), 1496 deletions(-)
 create mode 100644 test/llvm/operators/equal_comparison_test.cpp
 create mode 100644 test/llvm/operators/greater_than_test.cpp
 create mode 100644 test/llvm/operators/less_than_test.cpp
 create mode 100644 test/llvm/operators/logic/and_test.cpp
 create mode 100644 test/llvm/operators/logic/not_test.cpp
 create mode 100644 test/llvm/operators/logic/or_test.cpp
 create mode 100644 test/llvm/operators/math/abs_test.cpp
 create mode 100644 test/llvm/operators/math/acos_test.cpp
 create mode 100644 test/llvm/operators/math/add_test.cpp
 create mode 100644 test/llvm/operators/math/asin_test.cpp
 create mode 100644 test/llvm/operators/math/atan_test.cpp
 create mode 100644 test/llvm/operators/math/ceil_test.cpp
 create mode 100644 test/llvm/operators/math/cos_test.cpp
 create mode 100644 test/llvm/operators/math/divide_test.cpp
 create mode 100644 test/llvm/operators/math/exp10_test.cpp
 create mode 100644 test/llvm/operators/math/exp_test.cpp
 create mode 100644 test/llvm/operators/math/floor_test.cpp
 create mode 100644 test/llvm/operators/math/ln_test.cpp
 create mode 100644 test/llvm/operators/math/log10_test.cpp
 create mode 100644 test/llvm/operators/math/mod_test.cpp
 create mode 100644 test/llvm/operators/math/multiply_test.cpp
 create mode 100644 test/llvm/operators/math/random_int_test.cpp
 create mode 100644 test/llvm/operators/math/random_test.cpp
 create mode 100644 test/llvm/operators/math/round_test.cpp
 create mode 100644 test/llvm/operators/math/sin_test.cpp
 create mode 100644 test/llvm/operators/math/sqrt_test.cpp
 create mode 100644 test/llvm/operators/math/subtract_test.cpp
 create mode 100644 test/llvm/operators/math/tan_test.cpp
 create mode 100644 test/llvm/operators/string/string_char_test.cpp
 create mode 100644 test/llvm/operators/string/string_concat_test.cpp
 create mode 100644 test/llvm/operators/string/string_equal_case_insensitive_test.cpp
 create mode 100644 test/llvm/operators/string/string_equal_case_sensitive_test.cpp
 create mode 100644 test/llvm/operators/string/string_length_test.cpp

diff --git a/test/llvm/CMakeLists.txt b/test/llvm/CMakeLists.txt
index 9db31dd6..80ac82f6 100644
--- a/test/llvm/CMakeLists.txt
+++ b/test/llvm/CMakeLists.txt
@@ -22,6 +22,39 @@ add_executable(
   llvmexecutablecode_test.cpp
   llvmcodebuilder_test.cpp
   llvminstructionlist_test.cpp
+  operators/equal_comparison_test.cpp
+  operators/greater_than_test.cpp
+  operators/less_than_test.cpp
+  operators/math/add_test.cpp
+  operators/math/subtract_test.cpp
+  operators/math/multiply_test.cpp
+  operators/math/divide_test.cpp
+  operators/math/random_test.cpp
+  operators/math/random_int_test.cpp
+  operators/math/mod_test.cpp
+  operators/math/abs_test.cpp
+  operators/math/round_test.cpp
+  operators/math/floor_test.cpp
+  operators/math/ceil_test.cpp
+  operators/math/sqrt_test.cpp
+  operators/math/sin_test.cpp
+  operators/math/cos_test.cpp
+  operators/math/tan_test.cpp
+  operators/math/asin_test.cpp
+  operators/math/acos_test.cpp
+  operators/math/atan_test.cpp
+  operators/math/ln_test.cpp
+  operators/math/log10_test.cpp
+  operators/math/exp_test.cpp
+  operators/math/exp10_test.cpp
+  operators/logic/and_test.cpp
+  operators/logic/or_test.cpp
+  operators/logic/not_test.cpp
+  operators/string/string_equal_case_sensitive_test.cpp
+  operators/string/string_equal_case_insensitive_test.cpp
+  operators/string/string_concat_test.cpp
+  operators/string/string_char_test.cpp
+  operators/string/string_length_test.cpp
   type_analyzer/variabletypeafterbranch_test.cpp
   type_analyzer/variabletype_test.cpp
   type_analyzer/listtypeafterbranch_test.cpp
diff --git a/test/llvm/llvmcodebuilder_test.cpp b/test/llvm/llvmcodebuilder_test.cpp
index fcbed7b9..5d18511f 100644
--- a/test/llvm/llvmcodebuilder_test.cpp
+++ b/test/llvm/llvmcodebuilder_test.cpp
@@ -26,43 +26,6 @@ using ::testing::Eq;
 class LLVMCodeBuilderTest : public testing::Test
 {
     public:
-        enum class OpType
-        {
-            Add,
-            Sub,
-            Mul,
-            Div,
-            Random,
-            RandomInt,
-            CmpEQ,
-            CmpGT,
-            CmpLT,
-            StrCmpEQCS,
-            StrCmpEQCI,
-            And,
-            Or,
-            Not,
-            Mod,
-            Round,
-            Abs,
-            Floor,
-            Ceil,
-            Sqrt,
-            Sin,
-            Cos,
-            Tan,
-            Asin,
-            Acos,
-            Atan,
-            Ln,
-            Log10,
-            Exp,
-            Exp10,
-            StringConcat,
-            StringChar,
-            StringLength
-        };
-
         void SetUp() override
         {
             test_function(nullptr, nullptr, nullptr, nullptr, nullptr); // force dependency
@@ -108,333 +71,6 @@ class LLVMCodeBuilderTest : public testing::Test
             }
         }
 
-        CompilerValue *addOp(OpType type, CompilerValue *arg1, CompilerValue *arg2)
-        {
-            switch (type) {
-                case OpType::Add:
-                    return m_builder->createAdd(arg1, arg2);
-
-                case OpType::Sub:
-                    return m_builder->createSub(arg1, arg2);
-
-                case OpType::Mul:
-                    return m_builder->createMul(arg1, arg2);
-
-                case OpType::Div:
-                    return m_builder->createDiv(arg1, arg2);
-
-                case OpType::Random:
-                    return m_builder->createRandom(arg1, arg2);
-
-                case OpType::RandomInt:
-                    return m_builder->createRandomInt(arg1, arg2);
-
-                case OpType::CmpEQ:
-                    return m_builder->createCmpEQ(arg1, arg2);
-
-                case OpType::CmpGT:
-                    return m_builder->createCmpGT(arg1, arg2);
-
-                case OpType::CmpLT:
-                    return m_builder->createCmpLT(arg1, arg2);
-
-                case OpType::StrCmpEQCS:
-                    return m_builder->createStrCmpEQ(arg1, arg2, true);
-
-                case OpType::StrCmpEQCI:
-                    return m_builder->createStrCmpEQ(arg1, arg2, false);
-
-                case OpType::And:
-                    return m_builder->createAnd(arg1, arg2);
-
-                case OpType::Or:
-                    return m_builder->createOr(arg1, arg2);
-
-                case OpType::Mod:
-                    return m_builder->createMod(arg1, arg2);
-
-                case OpType::StringConcat:
-                    return m_builder->createStringConcat(arg1, arg2);
-
-                case OpType::StringChar:
-                    return m_builder->addStringChar(arg1, arg2);
-
-                default:
-                    EXPECT_TRUE(false);
-                    return nullptr;
-            }
-        }
-
-        CompilerValue *addOp(OpType type, CompilerValue *arg)
-        {
-            switch (type) {
-                case OpType::Not:
-                    return m_builder->createNot(arg);
-
-                case OpType::Round:
-                    return m_builder->createRound(arg);
-
-                case OpType::Abs:
-                    return m_builder->createAbs(arg);
-
-                case OpType::Floor:
-                    return m_builder->createFloor(arg);
-
-                case OpType::Ceil:
-                    return m_builder->createCeil(arg);
-
-                case OpType::Sqrt:
-                    return m_builder->createSqrt(arg);
-
-                case OpType::Sin:
-                    return m_builder->createSin(arg);
-
-                case OpType::Cos:
-                    return m_builder->createCos(arg);
-
-                case OpType::Tan:
-                    return m_builder->createTan(arg);
-
-                case OpType::Asin:
-                    return m_builder->createAsin(arg);
-
-                case OpType::Acos:
-                    return m_builder->createAcos(arg);
-
-                case OpType::Atan:
-                    return m_builder->createAtan(arg);
-
-                case OpType::Ln:
-                    return m_builder->createLn(arg);
-
-                case OpType::Log10:
-                    return m_builder->createLog10(arg);
-
-                case OpType::Exp:
-                    return m_builder->createExp(arg);
-
-                case OpType::Exp10:
-                    return m_builder->createExp10(arg);
-
-                case OpType::StringLength:
-                    return m_builder->addStringLength(arg);
-
-                default:
-                    EXPECT_TRUE(false);
-                    return nullptr;
-            }
-        }
-
-        Value doOp(OpType type, const Value &v1, const Value &v2)
-        {
-            switch (type) {
-                case OpType::Add:
-                    return v1 + v2;
-
-                case OpType::Sub:
-                    return v1 - v2;
-
-                case OpType::Mul:
-                    return v1 * v2;
-
-                case OpType::Div:
-                    return v1 / v2;
-
-                case OpType::Random: {
-                    const double sum = v1.toDouble() + v2.toDouble();
-
-                    if (std::isnan(sum) || std::isinf(sum))
-                        return sum;
-
-                    return v1.isInt() && v2.isInt() ? m_rng.randint(v1.toLong(), v2.toLong()) : m_rng.randintDouble(v1.toDouble(), v2.toDouble());
-                }
-
-                case OpType::RandomInt:
-                    return m_rng.randint(v1.toLong(), v2.toLong());
-
-                case OpType::CmpEQ:
-                    return v1 == v2;
-
-                case OpType::CmpGT:
-                    return v1 > v2;
-
-                case OpType::CmpLT:
-                    return v1 < v2;
-
-                case OpType::StrCmpEQCS:
-                    return string_compare_case_sensitive(value_toStringPtr(&v1.data()), value_toStringPtr(&v2.data())) == 0;
-
-                case OpType::StrCmpEQCI:
-                    return string_compare_case_insensitive(value_toStringPtr(&v1.data()), value_toStringPtr(&v2.data())) == 0;
-
-                case OpType::And:
-                    return v1.toBool() && v2.toBool();
-
-                case OpType::Or:
-                    return v1.toBool() || v2.toBool();
-
-                case OpType::Mod:
-                    return v1 % v2;
-
-                case OpType::StringConcat: {
-                    const StringPtr *string1 = value_toStringPtr(&v1.data());
-                    const StringPtr *string2 = value_toStringPtr(&v2.data());
-                    StringPtr *result = string_pool_new(true);
-
-                    result->size = string1->size + string2->size;
-                    string_alloc(result, result->size);
-                    memcpy(result->data, string1->data, string1->size * sizeof(typeof(*string1->data)));
-                    memcpy(result->data + string1->size, string2->data, (string2->size + 1) * sizeof(typeof(*string2->data))); // +1: null-terminate
-
-                    Value ret;
-                    value_assign_stringPtr(&ret.data(), result);
-                    return ret;
-                }
-
-                case OpType::StringChar: {
-                    const StringPtr *string = value_toStringPtr(&v1.data());
-                    const double index = v2.toDouble();
-                    const bool inRange = (index >= 0 && index < string->size);
-                    StringPtr *result = string_pool_new(true);
-
-                    string_alloc(result, 1);
-                    result->data[0] = inRange ? string->data[static_cast<size_t>(index)] : u'\0';
-                    result->data[1] = u'\0';
-                    result->size = inRange;
-
-                    Value ret;
-                    value_assign_stringPtr(&ret.data(), result);
-                    return ret;
-                }
-
-                default:
-                    EXPECT_TRUE(false);
-                    return Value();
-            }
-        }
-
-        Value doOp(OpType type, const Value &v)
-        {
-            switch (type) {
-                case OpType::Not:
-                    return !v.toBool();
-
-                case OpType::StringLength:
-                    return v.toUtf16().size();
-
-                default:
-                    EXPECT_TRUE(false);
-                    return Value();
-            }
-        }
-
-        void runOpTestCommon(OpType type, const Value &v1, const Value &v2)
-        {
-            createBuilder(true);
-
-            CompilerValue *arg1 = m_builder->addConstValue(v1);
-            CompilerValue *arg2 = m_builder->addConstValue(v2);
-            CompilerValue *ret = addOp(type, arg1, arg2);
-            m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { ret });
-
-            arg1 = m_builder->addConstValue(v1);
-            arg1 = callConstFuncForType(v1.type(), arg1);
-            arg2 = m_builder->addConstValue(v2);
-            arg2 = callConstFuncForType(v2.type(), arg2);
-            ret = addOp(type, arg1, arg2);
-            m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { ret });
-
-            auto code = m_builder->finalize();
-            Script script(&m_target, nullptr, nullptr);
-            script.setCode(code);
-            Thread thread(&m_target, nullptr, &script);
-            auto ctx = code->createExecutionContext(&thread);
-            ctx->setRng(&m_rng);
-
-            testing::internal::CaptureStdout();
-            code->run(ctx.get());
-        }
-
-        void checkOpTest(const Value &v1, const Value &v2, const std::string &expected)
-        {
-            const std::string quotes1 = v1.isString() ? "\"" : "";
-            const std::string quotes2 = v2.isString() ? "\"" : "";
-            ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << quotes1 << v1.toString() << quotes1 << " " << quotes2 << v2.toString() << quotes2;
-        }
-
-        void runOpTest(OpType type, const Value &v1, const Value &v2, const Value &expected)
-        {
-            std::string str = expected.toString();
-            runOpTestCommon(type, v1, v2);
-            checkOpTest(v1, v2, str + '\n' + str + '\n');
-        };
-
-        void runOpTest(OpType type, const Value &v1, const Value &v2)
-        {
-            runOpTestCommon(type, v1, v2);
-            std::string str = doOp(type, v1, v2).toString() + '\n';
-            std::string expected = str + str;
-            checkOpTest(v1, v2, expected);
-        };
-
-        void runOpTest(OpType type, const Value &v)
-        {
-            createBuilder(true);
-
-            CompilerValue *arg = m_builder->addConstValue(v);
-            CompilerValue *ret = addOp(type, arg);
-            m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { ret });
-
-            arg = m_builder->addConstValue(v);
-            arg = callConstFuncForType(v.type(), arg);
-            ret = addOp(type, arg);
-            m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { ret });
-
-            std::string str = doOp(type, v).toString() + '\n';
-            std::string expected = str + str;
-
-            auto code = m_builder->finalize();
-            Script script(&m_target, nullptr, nullptr);
-            script.setCode(code);
-            Thread thread(&m_target, nullptr, &script);
-            auto ctx = code->createExecutionContext(&thread);
-
-            testing::internal::CaptureStdout();
-            code->run(ctx.get());
-            const std::string quotes = v.isString() ? "\"" : "";
-            ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << "NOT: " << quotes << v.toString() << quotes;
-        };
-
-        void runUnaryNumOpTest(OpType type, const Value &v, double expectedResult)
-        {
-            createBuilder(true);
-
-            CompilerValue *arg = m_builder->addConstValue(v);
-            CompilerValue *ret = addOp(type, arg);
-            m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { ret });
-
-            arg = m_builder->addConstValue(v);
-            arg = callConstFuncForType(v.type(), arg);
-            ret = addOp(type, arg);
-            m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { ret });
-
-            std::stringstream stream;
-            stream << expectedResult;
-            std::string str = stream.str() + '\n';
-            std::string expected = str + str;
-
-            auto code = m_builder->finalize();
-            Script script(&m_target, nullptr, nullptr);
-            script.setCode(code);
-            Thread thread(&m_target, nullptr, &script);
-            auto ctx = code->createExecutionContext(&thread);
-
-            testing::internal::CaptureStdout();
-            code->run(ctx.get());
-            const std::string quotes = v.isString() ? "\"" : "";
-            ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << quotes << v.toString() << quotes;
-        };
-
         std::unordered_map<Target *, std::shared_ptr<LLVMCompilerContext>> m_contexts;
         std::vector<std::shared_ptr<LLVMCompilerContext>> m_contextList;
         std::unique_ptr<LLVMCodeBuilder> m_builder;
@@ -708,1138 +344,6 @@ TEST_F(LLVMCodeBuilderTest, RawValueCasting)
     ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
 }
 
-TEST_F(LLVMCodeBuilderTest, Add)
-{
-    runOpTest(OpType::Add, 50, 25);
-    runOpTest(OpType::Add, -500, 25);
-    runOpTest(OpType::Add, -500, -25);
-    runOpTest(OpType::Add, "2.54", "6.28");
-    runOpTest(OpType::Add, 2.54, "-6.28");
-    runOpTest(OpType::Add, true, true);
-    runOpTest(OpType::Add, "Infinity", "Infinity");
-    runOpTest(OpType::Add, "Infinity", "-Infinity");
-    runOpTest(OpType::Add, "-Infinity", "Infinity");
-    runOpTest(OpType::Add, "-Infinity", "-Infinity");
-    runOpTest(OpType::Add, 1, "NaN");
-    runOpTest(OpType::Add, "NaN", 1);
-}
-
-TEST_F(LLVMCodeBuilderTest, Subtract)
-{
-    runOpTest(OpType::Sub, 50, 25);
-    runOpTest(OpType::Sub, -500, 25);
-    runOpTest(OpType::Sub, -500, -25);
-    runOpTest(OpType::Sub, "2.54", "6.28");
-    runOpTest(OpType::Sub, 2.54, "-6.28");
-    runOpTest(OpType::Sub, true, true);
-    runOpTest(OpType::Sub, "Infinity", "Infinity");
-    runOpTest(OpType::Sub, "Infinity", "-Infinity");
-    runOpTest(OpType::Sub, "-Infinity", "Infinity");
-    runOpTest(OpType::Sub, "-Infinity", "-Infinity");
-    runOpTest(OpType::Sub, 1, "NaN");
-    runOpTest(OpType::Sub, "NaN", 1);
-}
-
-TEST_F(LLVMCodeBuilderTest, Multiply)
-{
-    runOpTest(OpType::Mul, 50, 2);
-    runOpTest(OpType::Mul, -500, 25);
-    runOpTest(OpType::Mul, "-500", -25);
-    runOpTest(OpType::Mul, "2.54", "6.28");
-    runOpTest(OpType::Mul, true, true);
-    runOpTest(OpType::Mul, "Infinity", "Infinity");
-    runOpTest(OpType::Mul, "Infinity", 0);
-    runOpTest(OpType::Mul, "Infinity", 2);
-    runOpTest(OpType::Mul, "Infinity", -2);
-    runOpTest(OpType::Mul, "Infinity", "-Infinity");
-    runOpTest(OpType::Mul, "-Infinity", "Infinity");
-    runOpTest(OpType::Mul, "-Infinity", 0);
-    runOpTest(OpType::Mul, "-Infinity", 2);
-    runOpTest(OpType::Mul, "-Infinity", -2);
-    runOpTest(OpType::Mul, "-Infinity", "-Infinity");
-    runOpTest(OpType::Mul, 1, "NaN");
-    runOpTest(OpType::Mul, "NaN", 1);
-}
-
-TEST_F(LLVMCodeBuilderTest, Divide)
-{
-    runOpTest(OpType::Div, 50, 2);
-    runOpTest(OpType::Div, -500, 25);
-    runOpTest(OpType::Div, "-500", -25);
-    runOpTest(OpType::Div, "3.5", "2.5");
-    runOpTest(OpType::Div, true, true);
-    runOpTest(OpType::Div, "Infinity", "Infinity");
-    runOpTest(OpType::Div, "Infinity", 0);
-    runOpTest(OpType::Div, "Infinity", 2);
-    runOpTest(OpType::Div, "Infinity", -2);
-    runOpTest(OpType::Div, "Infinity", "-Infinity");
-    runOpTest(OpType::Div, "-Infinity", "Infinity");
-    runOpTest(OpType::Div, "-Infinity", 0);
-    runOpTest(OpType::Div, "-Infinity", 2);
-    runOpTest(OpType::Div, "-Infinity", -2);
-    runOpTest(OpType::Div, "-Infinity", "-Infinity");
-    runOpTest(OpType::Div, 0, "Infinity");
-    runOpTest(OpType::Div, 2, "Infinity");
-    runOpTest(OpType::Div, -2, "Infinity");
-    runOpTest(OpType::Div, 0, "-Infinity");
-    runOpTest(OpType::Div, 2, "-Infinity");
-    runOpTest(OpType::Div, -2, "-Infinity");
-    runOpTest(OpType::Div, 1, "NaN");
-    runOpTest(OpType::Div, "NaN", 1);
-    runOpTest(OpType::Div, 5, 0);
-    runOpTest(OpType::Div, -5, 0);
-    runOpTest(OpType::Div, 0, 0);
-}
-
-TEST_F(LLVMCodeBuilderTest, Random)
-{
-    EXPECT_CALL(m_rng, randint(-45, 12)).Times(3).WillRepeatedly(Return(-18));
-    runOpTest(OpType::Random, -45, 12);
-
-    EXPECT_CALL(m_rng, randint(-45, 12)).Times(3).WillRepeatedly(Return(5));
-    runOpTest(OpType::Random, -45.0, 12.0);
-
-    EXPECT_CALL(m_rng, randintDouble(12, 6.05)).Times(3).WillRepeatedly(Return(3.486789));
-    runOpTest(OpType::Random, 12, 6.05);
-
-    EXPECT_CALL(m_rng, randintDouble(-78.686, -45)).Times(3).WillRepeatedly(Return(-59.468873));
-    runOpTest(OpType::Random, -78.686, -45);
-
-    EXPECT_CALL(m_rng, randintDouble(6.05, -78.686)).Times(3).WillRepeatedly(Return(-28.648764));
-    runOpTest(OpType::Random, 6.05, -78.686);
-
-    EXPECT_CALL(m_rng, randint(-45, 12)).Times(3).WillRepeatedly(Return(0));
-    runOpTest(OpType::Random, "-45", "12");
-
-    EXPECT_CALL(m_rng, randintDouble(-45, 12)).Times(3).WillRepeatedly(Return(5.2));
-    runOpTest(OpType::Random, "-45.0", "12");
-
-    EXPECT_CALL(m_rng, randintDouble(-45, 12)).Times(3).WillRepeatedly(Return(-15.5787));
-    runOpTest(OpType::Random, "-45", "12.0");
-
-    EXPECT_CALL(m_rng, randintDouble(-45, 12)).Times(3).WillRepeatedly(Return(2.587964));
-    runOpTest(OpType::Random, "-45.0", "12.0");
-
-    EXPECT_CALL(m_rng, randintDouble(6.05, -78.686)).Times(3).WillRepeatedly(Return(5.648764));
-    runOpTest(OpType::Random, "6.05", "-78.686");
-
-    EXPECT_CALL(m_rng, randint(-45, 12)).Times(3).WillRepeatedly(Return(0));
-    runOpTest(OpType::Random, "-45", 12);
-
-    EXPECT_CALL(m_rng, randint(-45, 12)).Times(3).WillRepeatedly(Return(0));
-    runOpTest(OpType::Random, -45, "12");
-
-    EXPECT_CALL(m_rng, randintDouble(-45, 12)).Times(3).WillRepeatedly(Return(5.2));
-    runOpTest(OpType::Random, "-45.0", 12);
-
-    EXPECT_CALL(m_rng, randintDouble(-45, 12)).Times(3).WillRepeatedly(Return(-15.5787));
-    runOpTest(OpType::Random, -45, "12.0");
-
-    EXPECT_CALL(m_rng, randintDouble(6.05, -78.686)).Times(3).WillRepeatedly(Return(5.648764));
-    runOpTest(OpType::Random, 6.05, "-78.686");
-
-    EXPECT_CALL(m_rng, randintDouble(6.05, -78.686)).Times(3).WillRepeatedly(Return(5.648764));
-    runOpTest(OpType::Random, "6.05", -78.686);
-
-    EXPECT_CALL(m_rng, randint(0, 1)).Times(3).WillRepeatedly(Return(1));
-    runOpTest(OpType::Random, false, true);
-
-    EXPECT_CALL(m_rng, randint(1, 5)).Times(3).WillRepeatedly(Return(1));
-    runOpTest(OpType::Random, true, 5);
-
-    EXPECT_CALL(m_rng, randint(8, 0)).Times(3).WillRepeatedly(Return(1));
-    runOpTest(OpType::Random, 8, false);
-
-    const double inf = std::numeric_limits<double>::infinity();
-    const double nan = std::numeric_limits<double>::quiet_NaN();
-
-    EXPECT_CALL(m_rng, randint(0, 5)).Times(3).WillRepeatedly(Return(5));
-    runOpTest(OpType::Random, nan, 5);
-
-    EXPECT_CALL(m_rng, randint(5, 0)).Times(3).WillRepeatedly(Return(3));
-    runOpTest(OpType::Random, 5, nan);
-
-    EXPECT_CALL(m_rng, randint(0, 0)).Times(3).WillRepeatedly(Return(0));
-    runOpTest(OpType::Random, nan, nan);
-
-    EXPECT_CALL(m_rng, randint).WillRepeatedly(Return(0));
-    EXPECT_CALL(m_rng, randintDouble).WillRepeatedly(Return(0));
-
-    runOpTest(OpType::Random, inf, 2, inf);
-    runOpTest(OpType::Random, -8, inf, inf);
-    runOpTest(OpType::Random, -inf, -2, -inf);
-    runOpTest(OpType::Random, 8, -inf, -inf);
-
-    runOpTest(OpType::Random, inf, 2.5, inf);
-    runOpTest(OpType::Random, -8.09, inf, inf);
-    runOpTest(OpType::Random, -inf, -2.5, -inf);
-    runOpTest(OpType::Random, 8.09, -inf, -inf);
-
-    runOpTest(OpType::Random, inf, inf, inf);
-    runOpTest(OpType::Random, -inf, -inf, -inf);
-    runOpTest(OpType::Random, inf, -inf, nan);
-    runOpTest(OpType::Random, -inf, inf, nan);
-}
-
-TEST_F(LLVMCodeBuilderTest, RandomInt)
-{
-    EXPECT_CALL(m_rng, randint(-45, 12)).Times(3).WillRepeatedly(Return(-18));
-    runOpTest(OpType::RandomInt, -45, 12);
-
-    EXPECT_CALL(m_rng, randint(-45, 12)).Times(3).WillRepeatedly(Return(5));
-    runOpTest(OpType::RandomInt, -45.0, 12.0);
-
-    EXPECT_CALL(m_rng, randint(12, 6)).Times(3).WillRepeatedly(Return(3));
-    runOpTest(OpType::RandomInt, 12, 6.05);
-
-    EXPECT_CALL(m_rng, randint(-78, -45)).Times(3).WillRepeatedly(Return(-59));
-    runOpTest(OpType::RandomInt, -78.686, -45);
-
-    EXPECT_CALL(m_rng, randint(-45, 12)).Times(3).WillRepeatedly(Return(0));
-    runOpTest(OpType::RandomInt, "-45", "12");
-
-    EXPECT_CALL(m_rng, randint(-45, 12)).Times(3).WillRepeatedly(Return(5));
-    runOpTest(OpType::RandomInt, "-45.0", "12");
-
-    EXPECT_CALL(m_rng, randint(-45, 12)).Times(3).WillRepeatedly(Return(-15));
-    runOpTest(OpType::RandomInt, "-45", "12.0");
-
-    EXPECT_CALL(m_rng, randint(0, 1)).Times(3).WillRepeatedly(Return(1));
-    runOpTest(OpType::RandomInt, false, true);
-
-    EXPECT_CALL(m_rng, randint(1, 5)).Times(3).WillRepeatedly(Return(1));
-    runOpTest(OpType::RandomInt, true, 5);
-
-    EXPECT_CALL(m_rng, randint(8, 0)).Times(3).WillRepeatedly(Return(1));
-    runOpTest(OpType::RandomInt, 8, false);
-
-    // NOTE: Infinity, -Infinity and NaN behavior is undefined
-}
-
-TEST_F(LLVMCodeBuilderTest, EqualComparison)
-{
-    runOpTest(OpType::CmpEQ, 10, 10);
-    runOpTest(OpType::CmpEQ, 10, 8);
-    runOpTest(OpType::CmpEQ, 8, 10);
-
-    runOpTest(OpType::CmpEQ, -4.25, -4.25);
-    runOpTest(OpType::CmpEQ, -4.25, 5.312);
-    runOpTest(OpType::CmpEQ, 5.312, -4.25);
-
-    runOpTest(OpType::CmpEQ, true, true);
-    runOpTest(OpType::CmpEQ, true, false);
-    runOpTest(OpType::CmpEQ, false, true);
-
-    runOpTest(OpType::CmpEQ, 1, true);
-    runOpTest(OpType::CmpEQ, 1, false);
-
-    runOpTest(OpType::CmpEQ, "abC def", "abC def");
-    runOpTest(OpType::CmpEQ, "abC def", "abc dEf");
-    runOpTest(OpType::CmpEQ, "abC def", "ghi Jkl");
-    runOpTest(OpType::CmpEQ, "abC def", "hello world");
-
-    runOpTest(OpType::CmpEQ, " ", "");
-    runOpTest(OpType::CmpEQ, " ", "0");
-    runOpTest(OpType::CmpEQ, " ", 0);
-    runOpTest(OpType::CmpEQ, 0, " ");
-    runOpTest(OpType::CmpEQ, "", "0");
-    runOpTest(OpType::CmpEQ, "", 0);
-    runOpTest(OpType::CmpEQ, 0, "");
-    runOpTest(OpType::CmpEQ, "0", 0);
-    runOpTest(OpType::CmpEQ, 0, "0");
-
-    runOpTest(OpType::CmpEQ, 5.25, "5.25");
-    runOpTest(OpType::CmpEQ, "5.25", 5.25);
-    runOpTest(OpType::CmpEQ, 5.25, " 5.25");
-    runOpTest(OpType::CmpEQ, " 5.25", 5.25);
-    runOpTest(OpType::CmpEQ, 5.25, "5.25 ");
-    runOpTest(OpType::CmpEQ, "5.25 ", 5.25);
-    runOpTest(OpType::CmpEQ, 5.25, " 5.25 ");
-    runOpTest(OpType::CmpEQ, " 5.25 ", 5.25);
-    runOpTest(OpType::CmpEQ, 5.25, "5.26");
-    runOpTest(OpType::CmpEQ, "5.26", 5.25);
-    runOpTest(OpType::CmpEQ, "5.25", "5.26");
-    runOpTest(OpType::CmpEQ, 5, "5  ");
-    runOpTest(OpType::CmpEQ, "5  ", 5);
-    runOpTest(OpType::CmpEQ, 0, "1");
-    runOpTest(OpType::CmpEQ, "1", 0);
-    runOpTest(OpType::CmpEQ, 0, "test");
-    runOpTest(OpType::CmpEQ, "test", 0);
-
-    static const double inf = std::numeric_limits<double>::infinity();
-    static const double nan = std::numeric_limits<double>::quiet_NaN();
-
-    runOpTest(OpType::CmpEQ, inf, inf);
-    runOpTest(OpType::CmpEQ, -inf, -inf);
-    runOpTest(OpType::CmpEQ, nan, nan);
-    runOpTest(OpType::CmpEQ, inf, -inf);
-    runOpTest(OpType::CmpEQ, -inf, inf);
-    runOpTest(OpType::CmpEQ, inf, nan);
-    runOpTest(OpType::CmpEQ, nan, inf);
-    runOpTest(OpType::CmpEQ, -inf, nan);
-    runOpTest(OpType::CmpEQ, nan, -inf);
-
-    runOpTest(OpType::CmpEQ, 5, inf);
-    runOpTest(OpType::CmpEQ, 5, -inf);
-    runOpTest(OpType::CmpEQ, 5, nan);
-    runOpTest(OpType::CmpEQ, 0, nan);
-
-    runOpTest(OpType::CmpEQ, true, "true");
-    runOpTest(OpType::CmpEQ, "true", true);
-    runOpTest(OpType::CmpEQ, false, "false");
-    runOpTest(OpType::CmpEQ, "false", false);
-    runOpTest(OpType::CmpEQ, false, "true");
-    runOpTest(OpType::CmpEQ, "true", false);
-    runOpTest(OpType::CmpEQ, true, "false");
-    runOpTest(OpType::CmpEQ, "false", true);
-    runOpTest(OpType::CmpEQ, true, "TRUE");
-    runOpTest(OpType::CmpEQ, "TRUE", true);
-    runOpTest(OpType::CmpEQ, false, "FALSE");
-    runOpTest(OpType::CmpEQ, "FALSE", false);
-
-    runOpTest(OpType::CmpEQ, true, "00001");
-    runOpTest(OpType::CmpEQ, "00001", true);
-    runOpTest(OpType::CmpEQ, true, "00000");
-    runOpTest(OpType::CmpEQ, "00000", true);
-    runOpTest(OpType::CmpEQ, false, "00000");
-    runOpTest(OpType::CmpEQ, "00000", false);
-
-    runOpTest(OpType::CmpEQ, "true", 1);
-    runOpTest(OpType::CmpEQ, 1, "true");
-    runOpTest(OpType::CmpEQ, "true", 0);
-    runOpTest(OpType::CmpEQ, 0, "true");
-    runOpTest(OpType::CmpEQ, "false", 0);
-    runOpTest(OpType::CmpEQ, 0, "false");
-    runOpTest(OpType::CmpEQ, "false", 1);
-    runOpTest(OpType::CmpEQ, 1, "false");
-
-    runOpTest(OpType::CmpEQ, "true", "TRUE");
-    runOpTest(OpType::CmpEQ, "true", "FALSE");
-    runOpTest(OpType::CmpEQ, "false", "FALSE");
-    runOpTest(OpType::CmpEQ, "false", "TRUE");
-
-    runOpTest(OpType::CmpEQ, true, inf);
-    runOpTest(OpType::CmpEQ, true, -inf);
-    runOpTest(OpType::CmpEQ, true, nan);
-    runOpTest(OpType::CmpEQ, false, inf);
-    runOpTest(OpType::CmpEQ, false, -inf);
-    runOpTest(OpType::CmpEQ, false, nan);
-
-    runOpTest(OpType::CmpEQ, "Infinity", inf);
-    runOpTest(OpType::CmpEQ, "Infinity", -inf);
-    runOpTest(OpType::CmpEQ, "Infinity", nan);
-    runOpTest(OpType::CmpEQ, "infinity", inf);
-    runOpTest(OpType::CmpEQ, "infinity", -inf);
-    runOpTest(OpType::CmpEQ, "infinity", nan);
-    runOpTest(OpType::CmpEQ, "-Infinity", inf);
-    runOpTest(OpType::CmpEQ, "-Infinity", -inf);
-    runOpTest(OpType::CmpEQ, "-Infinity", nan);
-    runOpTest(OpType::CmpEQ, "-infinity", inf);
-    runOpTest(OpType::CmpEQ, "-infinity", -inf);
-    runOpTest(OpType::CmpEQ, "-infinity", nan);
-    runOpTest(OpType::CmpEQ, "NaN", inf);
-    runOpTest(OpType::CmpEQ, "NaN", -inf);
-    runOpTest(OpType::CmpEQ, "NaN", nan);
-    runOpTest(OpType::CmpEQ, "nan", inf);
-    runOpTest(OpType::CmpEQ, "nan", -inf);
-    runOpTest(OpType::CmpEQ, "nan", nan);
-
-    runOpTest(OpType::CmpEQ, inf, "abc");
-    runOpTest(OpType::CmpEQ, inf, " ");
-    runOpTest(OpType::CmpEQ, inf, "");
-    runOpTest(OpType::CmpEQ, inf, "0");
-    runOpTest(OpType::CmpEQ, -inf, "abc");
-    runOpTest(OpType::CmpEQ, -inf, " ");
-    runOpTest(OpType::CmpEQ, -inf, "");
-    runOpTest(OpType::CmpEQ, -inf, "0");
-    runOpTest(OpType::CmpEQ, nan, "abc");
-    runOpTest(OpType::CmpEQ, nan, " ");
-    runOpTest(OpType::CmpEQ, nan, "");
-    runOpTest(OpType::CmpEQ, nan, "0");
-}
-
-TEST_F(LLVMCodeBuilderTest, GreaterAndLowerThanComparison)
-{
-    std::vector<OpType> opTypes = { OpType::CmpGT, OpType::CmpLT };
-
-    for (OpType type : opTypes) {
-        runOpTest(type, 10, 10);
-        runOpTest(type, 10, 8);
-        runOpTest(type, 8, 10);
-
-        runOpTest(type, -4.25, -4.25);
-        runOpTest(type, -4.25, 5.312);
-        runOpTest(type, 5.312, -4.25);
-
-        runOpTest(type, true, true);
-        runOpTest(type, true, false);
-        runOpTest(type, false, true);
-
-        runOpTest(type, 1, true);
-        runOpTest(type, 1, false);
-
-        runOpTest(type, "abC def", "abC def");
-        runOpTest(type, "abC def", "abc dEf");
-        runOpTest(type, "abC def", "ghi Jkl");
-        runOpTest(type, "ghi Jkl", "abC def");
-        runOpTest(type, "abC def", "hello world");
-
-        runOpTest(type, " ", "");
-        runOpTest(type, " ", "0");
-        runOpTest(type, " ", 0);
-        runOpTest(type, 0, " ");
-        runOpTest(type, "", "0");
-        runOpTest(type, "", 0);
-        runOpTest(type, 0, "");
-        runOpTest(type, "0", 0);
-        runOpTest(type, 0, "0");
-
-        runOpTest(type, 5.25, "5.25");
-        runOpTest(type, "5.25", 5.25);
-        runOpTest(type, 5.25, " 5.25");
-        runOpTest(type, " 5.25", 5.25);
-        runOpTest(type, 5.25, "5.25 ");
-        runOpTest(type, "5.25 ", 5.25);
-        runOpTest(type, 5.25, " 5.25 ");
-        runOpTest(type, " 5.25 ", 5.25);
-        runOpTest(type, 5.25, "5.26");
-        runOpTest(type, "5.26", 5.25);
-        runOpTest(type, "5.25", "5.26");
-        runOpTest(type, 5, "5  ");
-        runOpTest(type, "5  ", 5);
-        runOpTest(type, 0, "1");
-        runOpTest(type, "1", 0);
-        runOpTest(type, 0, "test");
-        runOpTest(type, "test", 0);
-        runOpTest(type, 55, "abc");
-        runOpTest(type, "abc", 55);
-
-        static const double inf = std::numeric_limits<double>::infinity();
-        static const double nan = std::numeric_limits<double>::quiet_NaN();
-
-        runOpTest(type, inf, inf);
-        runOpTest(type, -inf, -inf);
-        runOpTest(type, nan, nan);
-        runOpTest(type, inf, -inf);
-        runOpTest(type, -inf, inf);
-        runOpTest(type, inf, nan);
-        runOpTest(type, nan, inf);
-        runOpTest(type, -inf, nan);
-        runOpTest(type, nan, -inf);
-
-        runOpTest(type, 5, inf);
-        runOpTest(type, inf, 5);
-        runOpTest(type, 5, -inf);
-        runOpTest(type, -inf, 5);
-        runOpTest(type, 5, nan);
-        runOpTest(type, nan, 5);
-        runOpTest(type, 0, nan);
-        runOpTest(type, nan, 0);
-
-        runOpTest(type, true, "true");
-        runOpTest(type, "true", true);
-        runOpTest(type, false, "false");
-        runOpTest(type, "false", false);
-        runOpTest(type, false, "true");
-        runOpTest(type, "true", false);
-        runOpTest(type, true, "false");
-        runOpTest(type, "false", true);
-        runOpTest(type, true, "TRUE");
-        runOpTest(type, "TRUE", true);
-        runOpTest(type, false, "FALSE");
-        runOpTest(type, "FALSE", false);
-
-        runOpTest(type, true, "00001");
-        runOpTest(type, "00001", true);
-        runOpTest(type, true, "00000");
-        runOpTest(type, "00000", true);
-        runOpTest(type, false, "00000");
-        runOpTest(type, "00000", false);
-
-        runOpTest(type, "true", 1);
-        runOpTest(type, 1, "true");
-        runOpTest(type, "true", 0);
-        runOpTest(type, 0, "true");
-        runOpTest(type, "false", 0);
-        runOpTest(type, 0, "false");
-        runOpTest(type, "false", 1);
-        runOpTest(type, 1, "false");
-
-        runOpTest(type, "true", "TRUE");
-        runOpTest(type, "true", "FALSE");
-        runOpTest(type, "false", "FALSE");
-        runOpTest(type, "false", "TRUE");
-
-        runOpTest(type, true, inf);
-        runOpTest(type, inf, true);
-        runOpTest(type, true, -inf);
-        runOpTest(type, -inf, true);
-        runOpTest(type, true, nan);
-        runOpTest(type, nan, true);
-        runOpTest(type, false, inf);
-        runOpTest(type, inf, false);
-        runOpTest(type, false, -inf);
-        runOpTest(type, -inf, false);
-        runOpTest(type, false, nan);
-        runOpTest(type, nan, false);
-
-        runOpTest(type, "Infinity", inf);
-        runOpTest(type, "Infinity", -inf);
-        runOpTest(type, "Infinity", nan);
-        runOpTest(type, "infinity", inf);
-        runOpTest(type, "infinity", -inf);
-        runOpTest(type, "infinity", nan);
-        runOpTest(type, "-Infinity", inf);
-        runOpTest(type, "-Infinity", -inf);
-        runOpTest(type, "-Infinity", nan);
-        runOpTest(type, "-infinity", inf);
-        runOpTest(type, "-infinity", -inf);
-        runOpTest(type, "-infinity", nan);
-        runOpTest(type, "NaN", inf);
-        runOpTest(type, "NaN", -inf);
-        runOpTest(type, "NaN", nan);
-        runOpTest(type, "nan", inf);
-        runOpTest(type, "nan", -inf);
-        runOpTest(type, "nan", nan);
-
-        runOpTest(type, inf, "abc");
-        runOpTest(type, inf, " ");
-        runOpTest(type, inf, "");
-        runOpTest(type, inf, "0");
-        runOpTest(type, -inf, "abc");
-        runOpTest(type, -inf, " ");
-        runOpTest(type, -inf, "");
-        runOpTest(type, -inf, "0");
-        runOpTest(type, nan, "abc");
-        runOpTest(type, nan, " ");
-        runOpTest(type, nan, "");
-        runOpTest(type, nan, "0");
-    }
-}
-
-TEST_F(LLVMCodeBuilderTest, StringEqualComparison)
-{
-    std::vector<OpType> types = { OpType::StrCmpEQCS, OpType::StrCmpEQCI };
-
-    for (OpType type : types) {
-        runOpTest(type, 10, 10);
-        runOpTest(type, 10, 8);
-        runOpTest(type, 8, 10);
-
-        runOpTest(type, -4.25, -4.25);
-        runOpTest(type, -4.25, 5.312);
-        runOpTest(type, 5.312, -4.25);
-
-        runOpTest(type, true, true);
-        runOpTest(type, true, false);
-        runOpTest(type, false, true);
-
-        runOpTest(type, 1, true);
-        runOpTest(type, 1, false);
-
-        runOpTest(type, "abC def", "abC def");
-        runOpTest(type, "abC def", "abc dEf");
-        runOpTest(type, "abC def", "ghi Jkl");
-        runOpTest(type, "abC def", "hello world");
-
-        runOpTest(type, " ", "");
-        runOpTest(type, " ", "0");
-        runOpTest(type, " ", 0);
-        runOpTest(type, 0, " ");
-        runOpTest(type, "", "0");
-        runOpTest(type, "", 0);
-        runOpTest(type, 0, "");
-        runOpTest(type, "0", 0);
-        runOpTest(type, 0, "0");
-
-        runOpTest(type, 5.25, "5.25");
-        runOpTest(type, "5.25", 5.25);
-        runOpTest(type, 5.25, " 5.25");
-        runOpTest(type, " 5.25", 5.25);
-        runOpTest(type, 5.25, "5.25 ");
-        runOpTest(type, "5.25 ", 5.25);
-        runOpTest(type, 5.25, " 5.25 ");
-        runOpTest(type, " 5.25 ", 5.25);
-        runOpTest(type, 5.25, "5.26");
-        runOpTest(type, "5.26", 5.25);
-        runOpTest(type, "5.25", "5.26");
-        runOpTest(type, 5, "5  ");
-        runOpTest(type, "5  ", 5);
-        runOpTest(type, 0, "1");
-        runOpTest(type, "1", 0);
-        runOpTest(type, 0, "test");
-        runOpTest(type, "test", 0);
-
-        static const double inf = std::numeric_limits<double>::infinity();
-        static const double nan = std::numeric_limits<double>::quiet_NaN();
-
-        runOpTest(type, inf, inf);
-        runOpTest(type, -inf, -inf);
-        runOpTest(type, nan, nan);
-        runOpTest(type, inf, -inf);
-        runOpTest(type, -inf, inf);
-        runOpTest(type, inf, nan);
-        runOpTest(type, nan, inf);
-        runOpTest(type, -inf, nan);
-        runOpTest(type, nan, -inf);
-
-        runOpTest(type, 5, inf);
-        runOpTest(type, 5, -inf);
-        runOpTest(type, 5, nan);
-        runOpTest(type, 0, nan);
-
-        runOpTest(type, true, "true");
-        runOpTest(type, "true", true);
-        runOpTest(type, false, "false");
-        runOpTest(type, "false", false);
-        runOpTest(type, false, "true");
-        runOpTest(type, "true", false);
-        runOpTest(type, true, "false");
-        runOpTest(type, "false", true);
-        runOpTest(type, true, "TRUE");
-        runOpTest(type, "TRUE", true);
-        runOpTest(type, false, "FALSE");
-        runOpTest(type, "FALSE", false);
-
-        runOpTest(type, true, "00001");
-        runOpTest(type, "00001", true);
-        runOpTest(type, true, "00000");
-        runOpTest(type, "00000", true);
-        runOpTest(type, false, "00000");
-        runOpTest(type, "00000", false);
-
-        runOpTest(type, "true", 1);
-        runOpTest(type, 1, "true");
-        runOpTest(type, "true", 0);
-        runOpTest(type, 0, "true");
-        runOpTest(type, "false", 0);
-        runOpTest(type, 0, "false");
-        runOpTest(type, "false", 1);
-        runOpTest(type, 1, "false");
-
-        runOpTest(type, "true", "TRUE");
-        runOpTest(type, "true", "FALSE");
-        runOpTest(type, "false", "FALSE");
-        runOpTest(type, "false", "TRUE");
-
-        runOpTest(type, true, inf);
-        runOpTest(type, true, -inf);
-        runOpTest(type, true, nan);
-        runOpTest(type, false, inf);
-        runOpTest(type, false, -inf);
-        runOpTest(type, false, nan);
-
-        runOpTest(type, "Infinity", inf);
-        runOpTest(type, "Infinity", -inf);
-        runOpTest(type, "Infinity", nan);
-        runOpTest(type, "infinity", inf);
-        runOpTest(type, "infinity", -inf);
-        runOpTest(type, "infinity", nan);
-        runOpTest(type, "-Infinity", inf);
-        runOpTest(type, "-Infinity", -inf);
-        runOpTest(type, "-Infinity", nan);
-        runOpTest(type, "-infinity", inf);
-        runOpTest(type, "-infinity", -inf);
-        runOpTest(type, "-infinity", nan);
-        runOpTest(type, "NaN", inf);
-        runOpTest(type, "NaN", -inf);
-        runOpTest(type, "NaN", nan);
-        runOpTest(type, "nan", inf);
-        runOpTest(type, "nan", -inf);
-        runOpTest(type, "nan", nan);
-
-        runOpTest(type, inf, "abc");
-        runOpTest(type, inf, " ");
-        runOpTest(type, inf, "");
-        runOpTest(type, inf, "0");
-        runOpTest(type, -inf, "abc");
-        runOpTest(type, -inf, " ");
-        runOpTest(type, -inf, "");
-        runOpTest(type, -inf, "0");
-        runOpTest(type, nan, "abc");
-        runOpTest(type, nan, " ");
-        runOpTest(type, nan, "");
-        runOpTest(type, nan, "0");
-    }
-}
-
-TEST_F(LLVMCodeBuilderTest, AndOr)
-{
-    std::vector<OpType> opTypes = { OpType::And, OpType::Or };
-
-    for (OpType type : opTypes) {
-        runOpTest(type, 10, 8);
-        runOpTest(type, -4.25, -4.25);
-        runOpTest(type, -4.25, 5.312);
-
-        runOpTest(type, true, true);
-        runOpTest(type, true, false);
-        runOpTest(type, false, true);
-
-        runOpTest(type, 1, true);
-        runOpTest(type, 1, false);
-
-        runOpTest(type, "abc", "def");
-        runOpTest(type, "true", "true");
-        runOpTest(type, "true", "false");
-        runOpTest(type, "false", "true");
-        runOpTest(type, "false", "false");
-
-        runOpTest(type, 5.25, "5.25");
-        runOpTest(type, "5.25", 5.25);
-        runOpTest(type, 0, "1");
-        runOpTest(type, "1", 0);
-        runOpTest(type, 0, "test");
-        runOpTest(type, "test", 0);
-
-        static const double inf = std::numeric_limits<double>::infinity();
-        static const double nan = std::numeric_limits<double>::quiet_NaN();
-
-        runOpTest(type, inf, inf);
-        runOpTest(type, -inf, -inf);
-        runOpTest(type, nan, nan);
-        runOpTest(type, inf, -inf);
-        runOpTest(type, -inf, inf);
-        runOpTest(type, inf, nan);
-        runOpTest(type, nan, inf);
-        runOpTest(type, -inf, nan);
-        runOpTest(type, nan, -inf);
-
-        runOpTest(type, true, "true");
-        runOpTest(type, "true", true);
-        runOpTest(type, false, "false");
-        runOpTest(type, "false", false);
-        runOpTest(type, false, "true");
-        runOpTest(type, "true", false);
-        runOpTest(type, true, "false");
-        runOpTest(type, "false", true);
-        runOpTest(type, true, "TRUE");
-        runOpTest(type, "TRUE", true);
-        runOpTest(type, false, "FALSE");
-        runOpTest(type, "FALSE", false);
-
-        runOpTest(type, true, "00001");
-        runOpTest(type, "00001", true);
-        runOpTest(type, true, "00000");
-        runOpTest(type, "00000", true);
-        runOpTest(type, false, "00000");
-        runOpTest(type, "00000", false);
-
-        runOpTest(type, "true", 1);
-        runOpTest(type, 1, "true");
-        runOpTest(type, "true", 0);
-        runOpTest(type, 0, "true");
-        runOpTest(type, "false", 0);
-        runOpTest(type, 0, "false");
-        runOpTest(type, "false", 1);
-        runOpTest(type, 1, "false");
-
-        runOpTest(type, "true", "TRUE");
-        runOpTest(type, "true", "FALSE");
-        runOpTest(type, "false", "FALSE");
-        runOpTest(type, "false", "TRUE");
-
-        runOpTest(type, true, inf);
-        runOpTest(type, inf, true);
-        runOpTest(type, true, -inf);
-        runOpTest(type, -inf, true);
-        runOpTest(type, true, nan);
-        runOpTest(type, nan, true);
-        runOpTest(type, false, inf);
-        runOpTest(type, inf, false);
-        runOpTest(type, false, -inf);
-        runOpTest(type, -inf, false);
-        runOpTest(type, false, nan);
-        runOpTest(type, nan, false);
-
-        runOpTest(type, "Infinity", inf);
-        runOpTest(type, "Infinity", -inf);
-        runOpTest(type, "Infinity", nan);
-        runOpTest(type, "infinity", inf);
-        runOpTest(type, "infinity", -inf);
-        runOpTest(type, "infinity", nan);
-        runOpTest(type, "-Infinity", inf);
-        runOpTest(type, "-Infinity", -inf);
-        runOpTest(type, "-Infinity", nan);
-        runOpTest(type, "-infinity", inf);
-        runOpTest(type, "-infinity", -inf);
-        runOpTest(type, "-infinity", nan);
-        runOpTest(type, "NaN", inf);
-        runOpTest(type, "NaN", -inf);
-        runOpTest(type, "NaN", nan);
-        runOpTest(type, "nan", inf);
-        runOpTest(type, "nan", -inf);
-        runOpTest(type, "nan", nan);
-    }
-}
-
-TEST_F(LLVMCodeBuilderTest, Not)
-{
-    runOpTest(OpType::Not, 10);
-    runOpTest(OpType::Not, -4.25);
-    runOpTest(OpType::Not, 5.312);
-    runOpTest(OpType::Not, 1);
-    runOpTest(OpType::Not, 0);
-
-    runOpTest(OpType::Not, true);
-    runOpTest(OpType::Not, false);
-
-    runOpTest(OpType::Not, "abc");
-    runOpTest(OpType::Not, "5.25");
-    runOpTest(OpType::Not, "0");
-
-    static const double inf = std::numeric_limits<double>::infinity();
-    static const double nan = std::numeric_limits<double>::quiet_NaN();
-
-    runOpTest(OpType::Not, inf);
-    runOpTest(OpType::Not, -inf);
-    runOpTest(OpType::Not, nan);
-
-    runOpTest(OpType::Not, "true");
-    runOpTest(OpType::Not, "false");
-    runOpTest(OpType::Not, "TRUE");
-    runOpTest(OpType::Not, "FALSE");
-
-    runOpTest(OpType::Not, "00001");
-    runOpTest(OpType::Not, "00000");
-
-    runOpTest(OpType::Not, "Infinity");
-    runOpTest(OpType::Not, "infinity");
-    runOpTest(OpType::Not, "-Infinity");
-    runOpTest(OpType::Not, "-infinity");
-    runOpTest(OpType::Not, "NaN");
-    runOpTest(OpType::Not, "nan");
-}
-
-TEST_F(LLVMCodeBuilderTest, Mod)
-{
-    runOpTest(OpType::Mod, 4, 3);
-    runOpTest(OpType::Mod, 3, 3);
-    runOpTest(OpType::Mod, 2, 3);
-    runOpTest(OpType::Mod, 1, 3);
-    runOpTest(OpType::Mod, 0, 3);
-    runOpTest(OpType::Mod, -1, 3);
-    runOpTest(OpType::Mod, -2, 3);
-    runOpTest(OpType::Mod, -3, 3);
-    runOpTest(OpType::Mod, -4, 3);
-    runOpTest(OpType::Mod, 4.75, 2);
-    runOpTest(OpType::Mod, -4.75, 2);
-    runOpTest(OpType::Mod, -4.75, -2);
-    runOpTest(OpType::Mod, 4.75, -2);
-    runOpTest(OpType::Mod, 5, 0);
-    runOpTest(OpType::Mod, -5, 0);
-    runOpTest(OpType::Mod, -2.5, "Infinity");
-    runOpTest(OpType::Mod, -1.2, "-Infinity");
-    runOpTest(OpType::Mod, 2.5, "Infinity");
-    runOpTest(OpType::Mod, 1.2, "-Infinity");
-    runOpTest(OpType::Mod, "Infinity", 2);
-    runOpTest(OpType::Mod, "-Infinity", 2);
-    runOpTest(OpType::Mod, "Infinity", -2);
-    runOpTest(OpType::Mod, "-Infinity", -2);
-    runOpTest(OpType::Mod, 3, "NaN");
-    runOpTest(OpType::Mod, -3, "NaN");
-    runOpTest(OpType::Mod, "NaN", 5);
-    runOpTest(OpType::Mod, "NaN", -5);
-}
-
-TEST_F(LLVMCodeBuilderTest, Round)
-{
-    static const double inf = std::numeric_limits<double>::infinity();
-    static const double nan = std::numeric_limits<double>::quiet_NaN();
-
-    runUnaryNumOpTest(OpType::Round, 4.0, 4.0);
-    runUnaryNumOpTest(OpType::Round, 3.2, 3.0);
-    runUnaryNumOpTest(OpType::Round, 3.5, 4.0);
-    runUnaryNumOpTest(OpType::Round, 3.6, 4.0);
-    runUnaryNumOpTest(OpType::Round, -2.4, -2.0);
-    runUnaryNumOpTest(OpType::Round, -2.5, -2.0);
-    runUnaryNumOpTest(OpType::Round, -2.6, -3.0);
-    runUnaryNumOpTest(OpType::Round, -0.4, -0.0);
-    runUnaryNumOpTest(OpType::Round, -0.5, -0.0);
-    runUnaryNumOpTest(OpType::Round, -0.51, -1.0);
-    runUnaryNumOpTest(OpType::Round, inf, inf);
-    runUnaryNumOpTest(OpType::Round, -inf, -inf);
-    runUnaryNumOpTest(OpType::Round, nan, 0);
-}
-
-TEST_F(LLVMCodeBuilderTest, Abs)
-{
-    static const double inf = std::numeric_limits<double>::infinity();
-    static const double nan = std::numeric_limits<double>::quiet_NaN();
-
-    runUnaryNumOpTest(OpType::Abs, 4.0, 4.0);
-    runUnaryNumOpTest(OpType::Abs, 3.2, 3.2);
-    runUnaryNumOpTest(OpType::Abs, -2.0, 2.0);
-    runUnaryNumOpTest(OpType::Abs, -2.5, 2.5);
-    runUnaryNumOpTest(OpType::Abs, -2.6, 2.6);
-    runUnaryNumOpTest(OpType::Abs, 0.0, 0.0);
-    runUnaryNumOpTest(OpType::Abs, -0.0, 0.0);
-    runUnaryNumOpTest(OpType::Abs, inf, inf);
-    runUnaryNumOpTest(OpType::Abs, -inf, inf);
-    runUnaryNumOpTest(OpType::Abs, nan, 0);
-}
-
-TEST_F(LLVMCodeBuilderTest, Floor)
-{
-    static const double inf = std::numeric_limits<double>::infinity();
-    static const double nan = std::numeric_limits<double>::quiet_NaN();
-
-    runUnaryNumOpTest(OpType::Floor, 4.0, 4.0);
-    runUnaryNumOpTest(OpType::Floor, 3.2, 3.0);
-    runUnaryNumOpTest(OpType::Floor, 3.5, 3.0);
-    runUnaryNumOpTest(OpType::Floor, 3.6, 3.0);
-    runUnaryNumOpTest(OpType::Floor, 0.0, 0.0);
-    runUnaryNumOpTest(OpType::Floor, -0.0, -0.0);
-    runUnaryNumOpTest(OpType::Floor, -2.4, -3.0);
-    runUnaryNumOpTest(OpType::Floor, -2.5, -3.0);
-    runUnaryNumOpTest(OpType::Floor, -2.6, -3.0);
-    runUnaryNumOpTest(OpType::Floor, -0.4, -1.0);
-    runUnaryNumOpTest(OpType::Floor, -0.5, -1.0);
-    runUnaryNumOpTest(OpType::Floor, -0.51, -1.0);
-    runUnaryNumOpTest(OpType::Floor, inf, inf);
-    runUnaryNumOpTest(OpType::Floor, -inf, -inf);
-    runUnaryNumOpTest(OpType::Floor, nan, 0);
-}
-
-TEST_F(LLVMCodeBuilderTest, Ceil)
-{
-    static const double inf = std::numeric_limits<double>::infinity();
-    static const double nan = std::numeric_limits<double>::quiet_NaN();
-
-    runUnaryNumOpTest(OpType::Ceil, 8.0, 8.0);
-    runUnaryNumOpTest(OpType::Ceil, 3.2, 4.0);
-    runUnaryNumOpTest(OpType::Ceil, 3.5, 4.0);
-    runUnaryNumOpTest(OpType::Ceil, 3.6, 4.0);
-    runUnaryNumOpTest(OpType::Ceil, 0.4, 1.0);
-    runUnaryNumOpTest(OpType::Ceil, 0.0, 0.0);
-    runUnaryNumOpTest(OpType::Ceil, -0.0, -0.0);
-    runUnaryNumOpTest(OpType::Ceil, -2.4, -2.0);
-    runUnaryNumOpTest(OpType::Ceil, -2.5, -2.0);
-    runUnaryNumOpTest(OpType::Ceil, -2.6, -2.0);
-    runUnaryNumOpTest(OpType::Ceil, -0.4, -0.0);
-    runUnaryNumOpTest(OpType::Ceil, -0.5, -0.0);
-    runUnaryNumOpTest(OpType::Ceil, -0.51, -0.0);
-    runUnaryNumOpTest(OpType::Ceil, inf, inf);
-    runUnaryNumOpTest(OpType::Ceil, -inf, -inf);
-    runUnaryNumOpTest(OpType::Ceil, nan, 0);
-}
-
-TEST_F(LLVMCodeBuilderTest, Sqrt)
-{
-    static const double inf = std::numeric_limits<double>::infinity();
-    static const double nan = std::numeric_limits<double>::quiet_NaN();
-
-    runUnaryNumOpTest(OpType::Sqrt, 16.0, 4.0);
-    runUnaryNumOpTest(OpType::Sqrt, 0.04, 0.2);
-    runUnaryNumOpTest(OpType::Sqrt, 0.0, 0.0);
-    runUnaryNumOpTest(OpType::Sqrt, -0.0, 0.0);
-    runUnaryNumOpTest(OpType::Sqrt, -4.0, -nan); // negative NaN shouldn't be a problem
-    runUnaryNumOpTest(OpType::Sqrt, inf, inf);
-    runUnaryNumOpTest(OpType::Sqrt, -inf, -nan);
-    runUnaryNumOpTest(OpType::Sqrt, nan, 0);
-}
-
-TEST_F(LLVMCodeBuilderTest, Sin)
-{
-    static const double inf = std::numeric_limits<double>::infinity();
-    static const double nan = std::numeric_limits<double>::quiet_NaN();
-
-    runUnaryNumOpTest(OpType::Sin, 30.0, 0.5);
-    runUnaryNumOpTest(OpType::Sin, 90.0, 1.0);
-    runUnaryNumOpTest(OpType::Sin, 2.8e-9, 0.0);
-    runUnaryNumOpTest(OpType::Sin, 2.9e-9, 1e-10);
-    runUnaryNumOpTest(OpType::Sin, 570.0, -0.5);
-    runUnaryNumOpTest(OpType::Sin, -30.0, -0.5);
-    runUnaryNumOpTest(OpType::Sin, -90.0, -1.0);
-    runUnaryNumOpTest(OpType::Sin, 0.0, 0.0);
-    runUnaryNumOpTest(OpType::Sin, -0.0, 0.0);
-    runUnaryNumOpTest(OpType::Sin, inf, -nan); // negative NaN shouldn't be a problem
-    runUnaryNumOpTest(OpType::Sin, -inf, -nan);
-    runUnaryNumOpTest(OpType::Sin, nan, 0);
-}
-
-TEST_F(LLVMCodeBuilderTest, Cos)
-{
-    static const double inf = std::numeric_limits<double>::infinity();
-    static const double nan = std::numeric_limits<double>::quiet_NaN();
-
-    runUnaryNumOpTest(OpType::Cos, 60.0, 0.5);
-    runUnaryNumOpTest(OpType::Cos, 90.0, 0.0);
-    runUnaryNumOpTest(OpType::Cos, 600.0, -0.5);
-    runUnaryNumOpTest(OpType::Cos, 89.9999999971352, 1e-10);
-    runUnaryNumOpTest(OpType::Cos, 89.999999999, 0.0);
-    runUnaryNumOpTest(OpType::Cos, -60.0, 0.5);
-    runUnaryNumOpTest(OpType::Cos, -90.0, 0.0);
-    runUnaryNumOpTest(OpType::Cos, 0.0, 1.0);
-    runUnaryNumOpTest(OpType::Cos, -0.0, 1.0);
-    runUnaryNumOpTest(OpType::Cos, inf, -nan); // negative NaN shouldn't be a problem
-    runUnaryNumOpTest(OpType::Cos, -inf, -nan);
-    runUnaryNumOpTest(OpType::Cos, nan, 1.0);
-}
-
-TEST_F(LLVMCodeBuilderTest, Tan)
-{
-    static const double inf = std::numeric_limits<double>::infinity();
-    static const double nan = std::numeric_limits<double>::quiet_NaN();
-
-    runUnaryNumOpTest(OpType::Tan, 45.0, 1.0);
-    runUnaryNumOpTest(OpType::Tan, 90.0, inf);
-    runUnaryNumOpTest(OpType::Tan, 270.0, -inf);
-    runUnaryNumOpTest(OpType::Tan, 450.0, inf);
-    runUnaryNumOpTest(OpType::Tan, -90.0, -inf);
-    runUnaryNumOpTest(OpType::Tan, -270.0, inf);
-    runUnaryNumOpTest(OpType::Tan, -450.0, -inf);
-    runUnaryNumOpTest(OpType::Tan, 180.0, 0.0);
-    runUnaryNumOpTest(OpType::Tan, -180.0, 0.0);
-    runUnaryNumOpTest(OpType::Tan, 2.87e-9, 1e-10);
-    runUnaryNumOpTest(OpType::Tan, 2.8647e-9, 0.0);
-    runUnaryNumOpTest(OpType::Tan, 0.0, 0.0);
-    runUnaryNumOpTest(OpType::Tan, -0.0, 0.0);
-    runUnaryNumOpTest(OpType::Tan, inf, -nan); // negative NaN shouldn't be a problem
-    runUnaryNumOpTest(OpType::Tan, -inf, -nan);
-    runUnaryNumOpTest(OpType::Tan, nan, 0.0);
-}
-
-TEST_F(LLVMCodeBuilderTest, Asin)
-{
-    static const double inf = std::numeric_limits<double>::infinity();
-    static const double nan = std::numeric_limits<double>::quiet_NaN();
-
-    runUnaryNumOpTest(OpType::Asin, 1.0, 90.0);
-    runUnaryNumOpTest(OpType::Asin, 0.5, 30.0);
-    runUnaryNumOpTest(OpType::Asin, 0.0, 0.0);
-    runUnaryNumOpTest(OpType::Asin, -0.0, 0.0);
-    runUnaryNumOpTest(OpType::Asin, -0.5, -30.0);
-    runUnaryNumOpTest(OpType::Asin, -1.0, -90.0);
-    runUnaryNumOpTest(OpType::Asin, 1.1, nan);
-    runUnaryNumOpTest(OpType::Asin, -1.2, nan);
-    runUnaryNumOpTest(OpType::Asin, inf, nan);
-    runUnaryNumOpTest(OpType::Asin, -inf, nan);
-    runUnaryNumOpTest(OpType::Asin, nan, 0.0);
-}
-
-TEST_F(LLVMCodeBuilderTest, Acos)
-{
-    static const double inf = std::numeric_limits<double>::infinity();
-    static const double nan = std::numeric_limits<double>::quiet_NaN();
-
-    runUnaryNumOpTest(OpType::Acos, 1.0, 0.0);
-    runUnaryNumOpTest(OpType::Acos, 0.5, 60.0);
-    runUnaryNumOpTest(OpType::Acos, 0.0, 90.0);
-    runUnaryNumOpTest(OpType::Acos, -0.0, 90.0);
-    runUnaryNumOpTest(OpType::Acos, -0.5, 120.0);
-    runUnaryNumOpTest(OpType::Acos, -1.0, 180.0);
-    runUnaryNumOpTest(OpType::Acos, 1.1, nan);
-    runUnaryNumOpTest(OpType::Acos, -1.2, nan);
-    runUnaryNumOpTest(OpType::Acos, inf, nan);
-    runUnaryNumOpTest(OpType::Acos, -inf, nan);
-    runUnaryNumOpTest(OpType::Acos, nan, 90.0);
-}
-
-TEST_F(LLVMCodeBuilderTest, Atan)
-{
-    static const double inf = std::numeric_limits<double>::infinity();
-    static const double nan = std::numeric_limits<double>::quiet_NaN();
-
-    runUnaryNumOpTest(OpType::Atan, 1.0, 45.0);
-    runUnaryNumOpTest(OpType::Atan, 0.0, 0.0);
-    runUnaryNumOpTest(OpType::Atan, -0.0, -0.0);
-    runUnaryNumOpTest(OpType::Atan, -1.0, -45.0);
-    runUnaryNumOpTest(OpType::Atan, inf, 90.0);
-    runUnaryNumOpTest(OpType::Atan, -inf, -90.0);
-    runUnaryNumOpTest(OpType::Atan, nan, 0.0);
-}
-
-TEST_F(LLVMCodeBuilderTest, Ln)
-{
-    static const double inf = std::numeric_limits<double>::infinity();
-    static const double nan = std::numeric_limits<double>::quiet_NaN();
-
-    runUnaryNumOpTest(OpType::Ln, std::exp(1.0), 1.0);
-    runUnaryNumOpTest(OpType::Ln, std::exp(2.0), 2.0);
-    runUnaryNumOpTest(OpType::Ln, std::exp(0.3), 0.3);
-    runUnaryNumOpTest(OpType::Ln, 1.0, 0.0);
-    runUnaryNumOpTest(OpType::Ln, 0.0, -inf);
-    runUnaryNumOpTest(OpType::Ln, -0.0, -inf);
-    runUnaryNumOpTest(OpType::Ln, -0.7, -nan); // negative NaN shouldn't be a problem
-    runUnaryNumOpTest(OpType::Ln, inf, inf);
-    runUnaryNumOpTest(OpType::Ln, -inf, -nan);
-    runUnaryNumOpTest(OpType::Ln, nan, -inf);
-}
-
-TEST_F(LLVMCodeBuilderTest, Log10)
-{
-    static const double inf = std::numeric_limits<double>::infinity();
-    static const double nan = std::numeric_limits<double>::quiet_NaN();
-
-    runUnaryNumOpTest(OpType::Log10, 10.0, 1.0);
-    runUnaryNumOpTest(OpType::Log10, 1000.0, 3.0);
-    runUnaryNumOpTest(OpType::Log10, 0.01, -2.0);
-    runUnaryNumOpTest(OpType::Log10, 0.0, -inf);
-    runUnaryNumOpTest(OpType::Log10, -0.0, -inf);
-    runUnaryNumOpTest(OpType::Log10, -0.7, nan);
-    runUnaryNumOpTest(OpType::Log10, inf, inf);
-    runUnaryNumOpTest(OpType::Log10, -inf, nan);
-    runUnaryNumOpTest(OpType::Log10, nan, -inf);
-}
-
-TEST_F(LLVMCodeBuilderTest, Exp)
-{
-    static const double inf = std::numeric_limits<double>::infinity();
-    static const double nan = std::numeric_limits<double>::quiet_NaN();
-
-    runUnaryNumOpTest(OpType::Exp, 1.0, std::exp(1.0));
-    runUnaryNumOpTest(OpType::Exp, 0.5, std::exp(0.5));
-    runUnaryNumOpTest(OpType::Exp, 0.0, 1.0);
-    runUnaryNumOpTest(OpType::Exp, -0.0, 1.0);
-    runUnaryNumOpTest(OpType::Exp, -0.7, std::exp(-0.7));
-    runUnaryNumOpTest(OpType::Exp, inf, inf);
-    runUnaryNumOpTest(OpType::Exp, -inf, 0.0);
-    runUnaryNumOpTest(OpType::Exp, nan, 1.0);
-}
-
-TEST_F(LLVMCodeBuilderTest, Exp10)
-{
-    static const double inf = std::numeric_limits<double>::infinity();
-    static const double nan = std::numeric_limits<double>::quiet_NaN();
-
-    runUnaryNumOpTest(OpType::Exp10, 1.0, 10.0);
-    runUnaryNumOpTest(OpType::Exp10, 3.0, 1000.0);
-    runUnaryNumOpTest(OpType::Exp10, 0.0, 1.0);
-    runUnaryNumOpTest(OpType::Exp10, -0.0, 1.0);
-    runUnaryNumOpTest(OpType::Exp10, -1.0, 0.1);
-    runUnaryNumOpTest(OpType::Exp10, -5.0, 0.00001);
-    runUnaryNumOpTest(OpType::Exp10, inf, inf);
-    runUnaryNumOpTest(OpType::Exp10, -inf, 0.0);
-    runUnaryNumOpTest(OpType::Exp10, nan, 1.0);
-}
-
-TEST_F(LLVMCodeBuilderTest, StringConcat)
-{
-    runOpTest(OpType::StringConcat, "Hello ", "world");
-    runOpTest(OpType::StringConcat, "abc", "def");
-    runOpTest(OpType::StringConcat, "ábč", "ďéfgh");
-}
-
-TEST_F(LLVMCodeBuilderTest, StringChar)
-{
-    runOpTest(OpType::StringChar, "Hello world", 1);
-    runOpTest(OpType::StringChar, "Hello world", 0);
-    runOpTest(OpType::StringChar, "Hello world", 11);
-    runOpTest(OpType::StringChar, "abc", 2);
-    runOpTest(OpType::StringChar, "abc", -1);
-    runOpTest(OpType::StringChar, "abc", 3);
-    runOpTest(OpType::StringChar, "ábč", 0);
-}
-
-TEST_F(LLVMCodeBuilderTest, StringLength)
-{
-    runUnaryNumOpTest(OpType::StringLength, "Hello world", 11);
-    runUnaryNumOpTest(OpType::StringLength, "abc", 3);
-    runUnaryNumOpTest(OpType::StringLength, "abcdef", 6);
-    runUnaryNumOpTest(OpType::StringLength, "ábč", 3);
-}
-
 TEST_F(LLVMCodeBuilderTest, LocalVariables)
 {
     Stage stage;
diff --git a/test/llvm/operators/equal_comparison_test.cpp b/test/llvm/operators/equal_comparison_test.cpp
new file mode 100644
index 00000000..0e2c09a9
--- /dev/null
+++ b/test/llvm/operators/equal_comparison_test.cpp
@@ -0,0 +1,1205 @@
+#include <gtest/gtest.h>
+#include <scratchcpp/value.h>
+
+#include "llvmtestutils.h"
+
+class LLVMEqualComparisonTest : public testing::Test
+{
+    public:
+        LLVMTestUtils m_utils;
+};
+
+TEST_F(LLVMEqualComparisonTest, SameIntegers)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 10, 10);
+}
+
+TEST_F(LLVMEqualComparisonTest, SameIntegers_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 10, 10);
+}
+
+TEST_F(LLVMEqualComparisonTest, DifferentIntegers)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 10, 8);
+}
+
+TEST_F(LLVMEqualComparisonTest, DifferentIntegers_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 10, 8);
+}
+
+TEST_F(LLVMEqualComparisonTest, DifferentIntegersReversed)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 8, 10);
+}
+
+TEST_F(LLVMEqualComparisonTest, DifferentIntegersReversed_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 8, 10);
+}
+
+TEST_F(LLVMEqualComparisonTest, SameDecimals)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, -4.25, -4.25);
+}
+
+TEST_F(LLVMEqualComparisonTest, SameDecimals_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, -4.25, -4.25);
+}
+
+TEST_F(LLVMEqualComparisonTest, DifferentDecimals)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, -4.25, 5.312);
+}
+
+TEST_F(LLVMEqualComparisonTest, DifferentDecimals_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, -4.25, 5.312);
+}
+
+TEST_F(LLVMEqualComparisonTest, DifferentDecimalsReversed)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 5.312, -4.25);
+}
+
+TEST_F(LLVMEqualComparisonTest, DifferentDecimalsReversed_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 5.312, -4.25);
+}
+
+TEST_F(LLVMEqualComparisonTest, SameBooleans)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, true, true);
+}
+
+TEST_F(LLVMEqualComparisonTest, SameBooleans_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, true, true);
+}
+
+TEST_F(LLVMEqualComparisonTest, DifferentBooleans)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, true, false);
+}
+
+TEST_F(LLVMEqualComparisonTest, DifferentBooleans_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, true, false);
+}
+
+TEST_F(LLVMEqualComparisonTest, DifferentBooleansReversed)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, false, true);
+}
+
+TEST_F(LLVMEqualComparisonTest, DifferentBooleansReversed_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, false, true);
+}
+
+TEST_F(LLVMEqualComparisonTest, NumberWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 1, true);
+}
+
+TEST_F(LLVMEqualComparisonTest, NumberWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 1, true);
+}
+
+TEST_F(LLVMEqualComparisonTest, NumberWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 1, false);
+}
+
+TEST_F(LLVMEqualComparisonTest, NumberWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 1, false);
+}
+
+TEST_F(LLVMEqualComparisonTest, SameStrings)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "abC def", "abC def");
+}
+
+TEST_F(LLVMEqualComparisonTest, SameStrings_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "abC def", "abC def");
+}
+
+TEST_F(LLVMEqualComparisonTest, StringsCaseDifferent)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "abC def", "abc dEf");
+}
+
+TEST_F(LLVMEqualComparisonTest, StringsCaseDifferent_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "abC def", "abc dEf");
+}
+
+TEST_F(LLVMEqualComparisonTest, DifferentStrings)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "abC def", "ghi Jkl");
+}
+
+TEST_F(LLVMEqualComparisonTest, DifferentStrings_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "abC def", "ghi Jkl");
+}
+
+TEST_F(LLVMEqualComparisonTest, DifferentStringsLonger)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "abC def", "hello world");
+}
+
+TEST_F(LLVMEqualComparisonTest, DifferentStringsLonger_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "abC def", "hello world");
+}
+
+TEST_F(LLVMEqualComparisonTest, SpaceVsEmpty)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, " ", "");
+}
+
+TEST_F(LLVMEqualComparisonTest, SpaceVsEmpty_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, " ", "");
+}
+
+TEST_F(LLVMEqualComparisonTest, SpaceVsZeroString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, " ", "0");
+}
+
+TEST_F(LLVMEqualComparisonTest, SpaceVsZeroString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, " ", "0");
+}
+
+TEST_F(LLVMEqualComparisonTest, SpaceVsZeroNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, " ", 0);
+}
+
+TEST_F(LLVMEqualComparisonTest, SpaceVsZeroNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, " ", 0);
+}
+
+TEST_F(LLVMEqualComparisonTest, ZeroNumberVsSpace)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 0, " ");
+}
+
+TEST_F(LLVMEqualComparisonTest, ZeroNumberVsSpace_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 0, " ");
+}
+
+TEST_F(LLVMEqualComparisonTest, EmptyVsZeroString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "", "0");
+}
+
+TEST_F(LLVMEqualComparisonTest, EmptyVsZeroString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "", "0");
+}
+
+TEST_F(LLVMEqualComparisonTest, EmptyVsZeroNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "", 0);
+}
+
+TEST_F(LLVMEqualComparisonTest, EmptyVsZeroNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "", 0);
+}
+
+TEST_F(LLVMEqualComparisonTest, ZeroNumberVsEmpty)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 0, "");
+}
+
+TEST_F(LLVMEqualComparisonTest, ZeroNumberVsEmpty_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 0, "");
+}
+
+TEST_F(LLVMEqualComparisonTest, ZeroStringVsZeroNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "0", 0);
+}
+
+TEST_F(LLVMEqualComparisonTest, ZeroStringVsZeroNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "0", 0);
+}
+
+TEST_F(LLVMEqualComparisonTest, ZeroNumberVsZeroString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 0, "0");
+}
+
+TEST_F(LLVMEqualComparisonTest, ZeroNumberVsZeroString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 0, "0");
+}
+
+TEST_F(LLVMEqualComparisonTest, NumberVsExactString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 5.25, "5.25");
+}
+
+TEST_F(LLVMEqualComparisonTest, NumberVsExactString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 5.25, "5.25");
+}
+
+TEST_F(LLVMEqualComparisonTest, ExactStringVsNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "5.25", 5.25);
+}
+
+TEST_F(LLVMEqualComparisonTest, ExactStringVsNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "5.25", 5.25);
+}
+
+TEST_F(LLVMEqualComparisonTest, NumberVsStringWithLeadingSpace)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 5.25, " 5.25");
+}
+
+TEST_F(LLVMEqualComparisonTest, NumberVsStringWithLeadingSpace_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 5.25, " 5.25");
+}
+
+TEST_F(LLVMEqualComparisonTest, StringWithLeadingSpaceVsNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, " 5.25", 5.25);
+}
+
+TEST_F(LLVMEqualComparisonTest, StringWithLeadingSpaceVsNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, " 5.25", 5.25);
+}
+
+TEST_F(LLVMEqualComparisonTest, NumberVsStringWithTrailingSpace)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 5.25, "5.25 ");
+}
+
+TEST_F(LLVMEqualComparisonTest, NumberVsStringWithTrailingSpace_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 5.25, "5.25 ");
+}
+
+TEST_F(LLVMEqualComparisonTest, StringWithTrailingSpaceVsNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "5.25 ", 5.25);
+}
+
+TEST_F(LLVMEqualComparisonTest, StringWithTrailingSpaceVsNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "5.25 ", 5.25);
+}
+
+TEST_F(LLVMEqualComparisonTest, NumberVsStringWithSurroundingSpaces)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 5.25, " 5.25 ");
+}
+
+TEST_F(LLVMEqualComparisonTest, NumberVsStringWithSurroundingSpaces_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 5.25, " 5.25 ");
+}
+
+TEST_F(LLVMEqualComparisonTest, StringWithSurroundingSpacesVsNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, " 5.25 ", 5.25);
+}
+
+TEST_F(LLVMEqualComparisonTest, StringWithSurroundingSpacesVsNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, " 5.25 ", 5.25);
+}
+
+TEST_F(LLVMEqualComparisonTest, NumberVsDifferentString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 5.25, "5.26");
+}
+
+TEST_F(LLVMEqualComparisonTest, NumberVsDifferentString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 5.25, "5.26");
+}
+
+TEST_F(LLVMEqualComparisonTest, DifferentStringVsNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "5.26", 5.25);
+}
+
+TEST_F(LLVMEqualComparisonTest, DifferentStringVsNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "5.26", 5.25);
+}
+
+TEST_F(LLVMEqualComparisonTest, DifferentStringNumbers)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "5.25", "5.26");
+}
+
+TEST_F(LLVMEqualComparisonTest, DifferentStringNumbers_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "5.25", "5.26");
+}
+
+TEST_F(LLVMEqualComparisonTest, NumberVsStringWithTrailingSpaces)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 5, "5  ");
+}
+
+TEST_F(LLVMEqualComparisonTest, NumberVsStringWithTrailingSpaces_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 5, "5  ");
+}
+
+TEST_F(LLVMEqualComparisonTest, StringWithTrailingSpacesVsNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "5  ", 5);
+}
+
+TEST_F(LLVMEqualComparisonTest, StringWithTrailingSpacesVsNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "5  ", 5);
+}
+
+TEST_F(LLVMEqualComparisonTest, ZeroVsOneString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 0, "1");
+}
+
+TEST_F(LLVMEqualComparisonTest, ZeroVsOneString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 0, "1");
+}
+
+TEST_F(LLVMEqualComparisonTest, OneStringVsZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "1", 0);
+}
+
+TEST_F(LLVMEqualComparisonTest, OneStringVsZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "1", 0);
+}
+
+TEST_F(LLVMEqualComparisonTest, ZeroVsTestString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 0, "test");
+}
+
+TEST_F(LLVMEqualComparisonTest, ZeroVsTestString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 0, "test");
+}
+
+TEST_F(LLVMEqualComparisonTest, TestStringVsZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "test", 0);
+}
+
+TEST_F(LLVMEqualComparisonTest, TestStringVsZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "test", 0);
+}
+
+TEST_F(LLVMEqualComparisonTest, InfinityWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, InfinityWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, NegativeInfinityWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, NegativeInfinityWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, NaNWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "NaN", "NaN");
+}
+
+TEST_F(LLVMEqualComparisonTest, NaNWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "NaN", "NaN");
+}
+
+TEST_F(LLVMEqualComparisonTest, InfinityWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, InfinityWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, NegativeInfinityWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, NegativeInfinityWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, InfinityWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "Infinity", "NaN");
+}
+
+TEST_F(LLVMEqualComparisonTest, InfinityWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "Infinity", "NaN");
+}
+
+TEST_F(LLVMEqualComparisonTest, NaNWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "NaN", "Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, NaNWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "NaN", "Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, NegativeInfinityWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "-Infinity", "NaN");
+}
+
+TEST_F(LLVMEqualComparisonTest, NegativeInfinityWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "-Infinity", "NaN");
+}
+
+TEST_F(LLVMEqualComparisonTest, NaNWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "NaN", "-Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, NaNWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "NaN", "-Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, NumberWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 5, "Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, NumberWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 5, "Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, NumberWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 5, "-Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, NumberWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 5, "-Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, NumberWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 5, "NaN");
+}
+
+TEST_F(LLVMEqualComparisonTest, NumberWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 5, "NaN");
+}
+
+TEST_F(LLVMEqualComparisonTest, ZeroWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 0, "NaN");
+}
+
+TEST_F(LLVMEqualComparisonTest, ZeroWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 0, "NaN");
+}
+
+TEST_F(LLVMEqualComparisonTest, TrueBooleanWithTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, true, "true");
+}
+
+TEST_F(LLVMEqualComparisonTest, TrueBooleanWithTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, true, "true");
+}
+
+TEST_F(LLVMEqualComparisonTest, TrueStringWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "true", true);
+}
+
+TEST_F(LLVMEqualComparisonTest, FalseBooleanWithFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, false, "false");
+}
+
+TEST_F(LLVMEqualComparisonTest, FalseBooleanWithFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, false, "false");
+}
+
+TEST_F(LLVMEqualComparisonTest, FalseStringWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "false", false);
+}
+
+TEST_F(LLVMEqualComparisonTest, FalseStringWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "false", false);
+}
+
+TEST_F(LLVMEqualComparisonTest, FalseBooleanWithTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, false, "true");
+}
+
+TEST_F(LLVMEqualComparisonTest, FalseBooleanWithTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, false, "true");
+}
+
+TEST_F(LLVMEqualComparisonTest, TrueStringWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "true", false);
+}
+
+TEST_F(LLVMEqualComparisonTest, TrueStringWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "true", false);
+}
+
+TEST_F(LLVMEqualComparisonTest, TrueBooleanWithFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, true, "false");
+}
+
+TEST_F(LLVMEqualComparisonTest, TrueBooleanWithFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, true, "false");
+}
+
+TEST_F(LLVMEqualComparisonTest, FalseStringWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "false", true);
+}
+
+TEST_F(LLVMEqualComparisonTest, FalseStringWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "false", true);
+}
+
+TEST_F(LLVMEqualComparisonTest, TrueBooleanWithUppercaseTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, true, "TRUE");
+}
+
+TEST_F(LLVMEqualComparisonTest, TrueBooleanWithUppercaseTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, true, "TRUE");
+}
+
+TEST_F(LLVMEqualComparisonTest, UppercaseTrueStringWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "TRUE", true);
+}
+
+TEST_F(LLVMEqualComparisonTest, UppercaseTrueStringWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "TRUE", true);
+}
+
+TEST_F(LLVMEqualComparisonTest, FalseBooleanWithUppercaseFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, false, "FALSE");
+}
+
+TEST_F(LLVMEqualComparisonTest, FalseBooleanWithUppercaseFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, false, "FALSE");
+}
+
+TEST_F(LLVMEqualComparisonTest, UppercaseFalseStringWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "FALSE", false);
+}
+
+TEST_F(LLVMEqualComparisonTest, UppercaseFalseStringWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "FALSE", false);
+}
+
+TEST_F(LLVMEqualComparisonTest, TrueBooleanWithZeroPaddedOne)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, true, "00001");
+}
+
+TEST_F(LLVMEqualComparisonTest, TrueBooleanWithZeroPaddedOne_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, true, "00001");
+}
+
+TEST_F(LLVMEqualComparisonTest, ZeroPaddedOneWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "00001", true);
+}
+
+TEST_F(LLVMEqualComparisonTest, ZeroPaddedOneWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "00001", true);
+}
+
+TEST_F(LLVMEqualComparisonTest, TrueBooleanWithZeroPaddedZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, true, "00000");
+}
+
+TEST_F(LLVMEqualComparisonTest, TrueBooleanWithZeroPaddedZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, true, "00000");
+}
+
+TEST_F(LLVMEqualComparisonTest, ZeroPaddedZeroWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "00000", true);
+}
+
+TEST_F(LLVMEqualComparisonTest, ZeroPaddedZeroWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "00000", true);
+}
+
+TEST_F(LLVMEqualComparisonTest, FalseBooleanWithZeroPaddedZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, false, "00000");
+}
+
+TEST_F(LLVMEqualComparisonTest, FalseBooleanWithZeroPaddedZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, false, "00000");
+}
+
+TEST_F(LLVMEqualComparisonTest, ZeroPaddedZeroWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "00000", false);
+}
+
+TEST_F(LLVMEqualComparisonTest, ZeroPaddedZeroWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "00000", false);
+}
+
+TEST_F(LLVMEqualComparisonTest, TrueStringWithOne)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "true", 1);
+}
+
+TEST_F(LLVMEqualComparisonTest, TrueStringWithOne_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "true", 1);
+}
+
+TEST_F(LLVMEqualComparisonTest, OneWithTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 1, "true");
+}
+
+TEST_F(LLVMEqualComparisonTest, OneWithTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 1, "true");
+}
+
+TEST_F(LLVMEqualComparisonTest, TrueStringWithZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "true", 0);
+}
+
+TEST_F(LLVMEqualComparisonTest, TrueStringWithZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "true", 0);
+}
+
+TEST_F(LLVMEqualComparisonTest, ZeroWithTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 0, "true");
+}
+
+TEST_F(LLVMEqualComparisonTest, ZeroWithTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 0, "true");
+}
+
+TEST_F(LLVMEqualComparisonTest, FalseStringWithZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "false", 0);
+}
+
+TEST_F(LLVMEqualComparisonTest, FalseStringWithZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "false", 0);
+}
+
+TEST_F(LLVMEqualComparisonTest, ZeroWithFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 0, "false");
+}
+
+TEST_F(LLVMEqualComparisonTest, ZeroWithFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 0, "false");
+}
+
+TEST_F(LLVMEqualComparisonTest, FalseStringWithOne)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "false", 1);
+}
+
+TEST_F(LLVMEqualComparisonTest, FalseStringWithOne_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "false", 1);
+}
+
+TEST_F(LLVMEqualComparisonTest, OneWithFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, 1, "false");
+}
+
+TEST_F(LLVMEqualComparisonTest, OneWithFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, 1, "false");
+}
+
+TEST_F(LLVMEqualComparisonTest, TrueStringWithUppercaseTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "true", "TRUE");
+}
+
+TEST_F(LLVMEqualComparisonTest, TrueStringWithUppercaseTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "true", "TRUE");
+}
+
+TEST_F(LLVMEqualComparisonTest, TrueStringWithUppercaseFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "true", "FALSE");
+}
+
+TEST_F(LLVMEqualComparisonTest, TrueStringWithUppercaseFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "true", "FALSE");
+}
+
+TEST_F(LLVMEqualComparisonTest, FalseStringWithUppercaseFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "false", "FALSE");
+}
+
+TEST_F(LLVMEqualComparisonTest, FalseStringWithUppercaseFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "false", "FALSE");
+}
+
+TEST_F(LLVMEqualComparisonTest, FalseStringWithUppercaseTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "false", "TRUE");
+}
+
+TEST_F(LLVMEqualComparisonTest, FalseStringWithUppercaseTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "false", "TRUE");
+}
+
+TEST_F(LLVMEqualComparisonTest, TrueBooleanWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, true, "Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, TrueBooleanWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, true, "Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, TrueBooleanWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, true, "-Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, TrueBooleanWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, true, "-Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, TrueBooleanWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, true, "NaN");
+}
+
+TEST_F(LLVMEqualComparisonTest, TrueBooleanWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, true, "NaN");
+}
+
+TEST_F(LLVMEqualComparisonTest, FalseBooleanWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, false, "Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, FalseBooleanWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, false, "Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, FalseBooleanWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, false, "-Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, FalseBooleanWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, false, "-Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, FalseBooleanWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, false, "NaN");
+}
+
+TEST_F(LLVMEqualComparisonTest, FalseBooleanWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, false, "NaN");
+}
+
+TEST_F(LLVMEqualComparisonTest, InfinityStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, InfinityStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, InfinityStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, InfinityStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, InfinityStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "Infinity", "NaN");
+}
+
+TEST_F(LLVMEqualComparisonTest, InfinityStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "Infinity", "NaN");
+}
+
+TEST_F(LLVMEqualComparisonTest, LowercaseInfinityStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "infinity", "Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, LowercaseInfinityStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "infinity", "Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, LowercaseInfinityStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "infinity", "-Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, LowercaseInfinityStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "infinity", "-Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, LowercaseInfinityStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "infinity", "NaN");
+}
+
+TEST_F(LLVMEqualComparisonTest, LowercaseInfinityStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "infinity", "NaN");
+}
+
+TEST_F(LLVMEqualComparisonTest, NegativeInfinityStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, NegativeInfinityStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, NegativeInfinityStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, NegativeInfinityStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, NegativeInfinityStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "-Infinity", "NaN");
+}
+
+TEST_F(LLVMEqualComparisonTest, NegativeInfinityStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "-Infinity", "NaN");
+}
+
+TEST_F(LLVMEqualComparisonTest, LowercaseNegativeInfinityStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "-infinity", "Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, LowercaseNegativeInfinityStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "-infinity", "Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, LowercaseNegativeInfinityStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "-infinity", "-Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, LowercaseNegativeInfinityStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "-infinity", "-Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, LowercaseNegativeInfinityStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "-infinity", "NaN");
+}
+
+TEST_F(LLVMEqualComparisonTest, LowercaseNegativeInfinityStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "-infinity", "NaN");
+}
+
+TEST_F(LLVMEqualComparisonTest, NaNStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "NaN", "Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, NaNStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "NaN", "Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, NaNStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "NaN", "-Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, NaNStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "NaN", "-Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, NaNStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "NaN", "NaN");
+}
+
+TEST_F(LLVMEqualComparisonTest, NaNStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "NaN", "NaN");
+}
+
+TEST_F(LLVMEqualComparisonTest, LowercaseNaNStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "nan", "Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, LowercaseNaNStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "nan", "Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, LowercaseNaNStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "nan", "-Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, LowercaseNaNStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "nan", "-Infinity");
+}
+
+TEST_F(LLVMEqualComparisonTest, LowercaseNaNStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "nan", "NaN");
+}
+
+TEST_F(LLVMEqualComparisonTest, LowercaseNaNStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "nan", "NaN");
+}
+
+TEST_F(LLVMEqualComparisonTest, InfinityWithStringAbc)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "Infinity", "abc");
+}
+
+TEST_F(LLVMEqualComparisonTest, InfinityWithStringAbc_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "Infinity", "abc");
+}
+
+TEST_F(LLVMEqualComparisonTest, InfinityWithStringSpace)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "Infinity", " ");
+}
+
+TEST_F(LLVMEqualComparisonTest, InfinityWithStringSpace_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "Infinity", " ");
+}
+
+TEST_F(LLVMEqualComparisonTest, InfinityWithEmptyString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "Infinity", "");
+}
+
+TEST_F(LLVMEqualComparisonTest, InfinityWithEmptyString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "Infinity", "");
+}
+
+TEST_F(LLVMEqualComparisonTest, InfinityWithZeroString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "Infinity", "0");
+}
+
+TEST_F(LLVMEqualComparisonTest, InfinityWithZeroString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "Infinity", "0");
+}
+
+TEST_F(LLVMEqualComparisonTest, NegativeInfinityWithStringAbc)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "-Infinity", "abc");
+}
+
+TEST_F(LLVMEqualComparisonTest, NegativeInfinityWithStringAbc_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "-Infinity", "abc");
+}
+
+TEST_F(LLVMEqualComparisonTest, NegativeInfinityWithStringSpace)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "-Infinity", " ");
+}
+
+TEST_F(LLVMEqualComparisonTest, NegativeInfinityWithStringSpace_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "-Infinity", " ");
+}
+
+TEST_F(LLVMEqualComparisonTest, NegativeInfinityWithEmptyString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "-Infinity", "");
+}
+
+TEST_F(LLVMEqualComparisonTest, NegativeInfinityWithEmptyString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "-Infinity", "");
+}
+
+TEST_F(LLVMEqualComparisonTest, NegativeInfinityWithZeroString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "-Infinity", "0");
+}
+
+TEST_F(LLVMEqualComparisonTest, NegativeInfinityWithZeroString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "-Infinity", "0");
+}
+
+TEST_F(LLVMEqualComparisonTest, NaNWithStringAbc)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "NaN", "abc");
+}
+
+TEST_F(LLVMEqualComparisonTest, NaNWithStringAbc_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "NaN", "abc");
+}
+
+TEST_F(LLVMEqualComparisonTest, NaNWithStringSpace)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "NaN", " ");
+}
+
+TEST_F(LLVMEqualComparisonTest, NaNWithStringSpace_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "NaN", " ");
+}
+
+TEST_F(LLVMEqualComparisonTest, NaNWithEmptyString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "NaN", "");
+}
+
+TEST_F(LLVMEqualComparisonTest, NaNWithEmptyString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "NaN", "");
+}
+
+TEST_F(LLVMEqualComparisonTest, NaNWithZeroString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, false, "NaN", "0");
+}
+
+TEST_F(LLVMEqualComparisonTest, NaNWithZeroString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpEQ, true, "NaN", "0");
+}
diff --git a/test/llvm/operators/greater_than_test.cpp b/test/llvm/operators/greater_than_test.cpp
new file mode 100644
index 00000000..9256def5
--- /dev/null
+++ b/test/llvm/operators/greater_than_test.cpp
@@ -0,0 +1,1340 @@
+#include <gtest/gtest.h>
+#include <scratchcpp/value.h>
+
+#include "llvmtestutils.h"
+
+class LLVMGreaterThanTest : public testing::Test
+{
+    public:
+        LLVMTestUtils m_utils;
+};
+
+TEST_F(LLVMGreaterThanTest, SameIntegers)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 10, 10);
+}
+
+TEST_F(LLVMGreaterThanTest, SameIntegers_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 10, 10);
+}
+
+TEST_F(LLVMGreaterThanTest, FirstGreaterInteger)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 10, 8);
+}
+
+TEST_F(LLVMGreaterThanTest, FirstGreaterInteger_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 10, 8);
+}
+
+TEST_F(LLVMGreaterThanTest, SecondGreaterInteger)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 8, 10);
+}
+
+TEST_F(LLVMGreaterThanTest, SecondGreaterInteger_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 8, 10);
+}
+
+TEST_F(LLVMGreaterThanTest, SameDecimals)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, -4.25, -4.25);
+}
+
+TEST_F(LLVMGreaterThanTest, SameDecimals_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, -4.25, -4.25);
+}
+
+TEST_F(LLVMGreaterThanTest, FirstGreaterDecimal)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, -4.25, 5.312);
+}
+
+TEST_F(LLVMGreaterThanTest, FirstGreaterDecimal_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, -4.25, 5.312);
+}
+
+TEST_F(LLVMGreaterThanTest, SecondGreaterDecimal)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 5.312, -4.25);
+}
+
+TEST_F(LLVMGreaterThanTest, SecondGreaterDecimal_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 5.312, -4.25);
+}
+
+TEST_F(LLVMGreaterThanTest, SameBooleans)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, true, true);
+}
+
+TEST_F(LLVMGreaterThanTest, SameBooleans_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, true, true);
+}
+
+TEST_F(LLVMGreaterThanTest, TrueGreaterThanFalse)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, true, false);
+}
+
+TEST_F(LLVMGreaterThanTest, TrueGreaterThanFalse_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, true, false);
+}
+
+TEST_F(LLVMGreaterThanTest, FalseGreaterThanTrue)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, false, true);
+}
+
+TEST_F(LLVMGreaterThanTest, FalseGreaterThanTrue_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, false, true);
+}
+
+TEST_F(LLVMGreaterThanTest, NumberGreaterThanTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 1, true);
+}
+
+TEST_F(LLVMGreaterThanTest, NumberGreaterThanTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 1, true);
+}
+
+TEST_F(LLVMGreaterThanTest, NumberGreaterThanFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 1, false);
+}
+
+TEST_F(LLVMGreaterThanTest, NumberGreaterThanFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 1, false);
+}
+
+TEST_F(LLVMGreaterThanTest, SameStrings)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "abC def", "abC def");
+}
+
+TEST_F(LLVMGreaterThanTest, SameStrings_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "abC def", "abC def");
+}
+
+TEST_F(LLVMGreaterThanTest, StringsCaseDifferent)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "abC def", "abc dEf");
+}
+
+TEST_F(LLVMGreaterThanTest, StringsCaseDifferent_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "abC def", "abc dEf");
+}
+
+TEST_F(LLVMGreaterThanTest, FirstStringGreater)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "abC def", "ghi Jkl");
+}
+
+TEST_F(LLVMGreaterThanTest, FirstStringGreater_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "abC def", "ghi Jkl");
+}
+
+TEST_F(LLVMGreaterThanTest, SecondStringGreater)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "ghi Jkl", "abC def");
+}
+
+TEST_F(LLVMGreaterThanTest, SecondStringGreater_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "ghi Jkl", "abC def");
+}
+
+TEST_F(LLVMGreaterThanTest, StringsLengthComparison)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "abC def", "hello world");
+}
+
+TEST_F(LLVMGreaterThanTest, StringsLengthComparison_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "abC def", "hello world");
+}
+
+TEST_F(LLVMGreaterThanTest, SpaceGreaterThanEmpty)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, " ", "");
+}
+
+TEST_F(LLVMGreaterThanTest, SpaceGreaterThanEmpty_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, " ", "");
+}
+
+TEST_F(LLVMGreaterThanTest, SpaceGreaterThanZeroString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, " ", "0");
+}
+
+TEST_F(LLVMGreaterThanTest, SpaceGreaterThanZeroString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, " ", "0");
+}
+
+TEST_F(LLVMGreaterThanTest, SpaceGreaterThanZeroNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, " ", 0);
+}
+
+TEST_F(LLVMGreaterThanTest, SpaceGreaterThanZeroNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, " ", 0);
+}
+
+TEST_F(LLVMGreaterThanTest, ZeroNumberGreaterThanSpace)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 0, " ");
+}
+
+TEST_F(LLVMGreaterThanTest, ZeroNumberGreaterThanSpace_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 0, " ");
+}
+
+TEST_F(LLVMGreaterThanTest, EmptyGreaterThanZeroString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "", "0");
+}
+
+TEST_F(LLVMGreaterThanTest, EmptyGreaterThanZeroString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "", "0");
+}
+
+TEST_F(LLVMGreaterThanTest, EmptyGreaterThanZeroNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "", 0);
+}
+
+TEST_F(LLVMGreaterThanTest, EmptyGreaterThanZeroNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "", 0);
+}
+
+TEST_F(LLVMGreaterThanTest, ZeroNumberGreaterThanEmpty)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 0, "");
+}
+
+TEST_F(LLVMGreaterThanTest, ZeroNumberGreaterThanEmpty_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 0, "");
+}
+
+TEST_F(LLVMGreaterThanTest, ZeroStringGreaterThanZeroNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "0", 0);
+}
+
+TEST_F(LLVMGreaterThanTest, ZeroStringGreaterThanZeroNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "0", 0);
+}
+
+TEST_F(LLVMGreaterThanTest, ZeroNumberGreaterThanZeroString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 0, "0");
+}
+
+TEST_F(LLVMGreaterThanTest, ZeroNumberGreaterThanZeroString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 0, "0");
+}
+
+TEST_F(LLVMGreaterThanTest, NumberGreaterThanExactString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 5.25, "5.25");
+}
+
+TEST_F(LLVMGreaterThanTest, NumberGreaterThanExactString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 5.25, "5.25");
+}
+
+TEST_F(LLVMGreaterThanTest, ExactStringGreaterThanNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "5.25", 5.25);
+}
+
+TEST_F(LLVMGreaterThanTest, ExactStringGreaterThanNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "5.25", 5.25);
+}
+
+TEST_F(LLVMGreaterThanTest, NumberGreaterThanStringWithLeadingSpace)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 5.25, " 5.25");
+}
+
+TEST_F(LLVMGreaterThanTest, NumberGreaterThanStringWithLeadingSpace_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 5.25, " 5.25");
+}
+
+TEST_F(LLVMGreaterThanTest, StringWithLeadingSpaceGreaterThanNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, " 5.25", 5.25);
+}
+
+TEST_F(LLVMGreaterThanTest, StringWithLeadingSpaceGreaterThanNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, " 5.25", 5.25);
+}
+
+TEST_F(LLVMGreaterThanTest, NumberGreaterThanStringWithTrailingSpace)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 5.25, "5.25 ");
+}
+
+TEST_F(LLVMGreaterThanTest, NumberGreaterThanStringWithTrailingSpace_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 5.25, "5.25 ");
+}
+
+TEST_F(LLVMGreaterThanTest, StringWithTrailingSpaceGreaterThanNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "5.25 ", 5.25);
+}
+
+TEST_F(LLVMGreaterThanTest, StringWithTrailingSpaceGreaterThanNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "5.25 ", 5.25);
+}
+
+TEST_F(LLVMGreaterThanTest, NumberGreaterThanStringWithSurroundingSpaces)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 5.25, " 5.25 ");
+}
+
+TEST_F(LLVMGreaterThanTest, NumberGreaterThanStringWithSurroundingSpaces_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 5.25, " 5.25 ");
+}
+
+TEST_F(LLVMGreaterThanTest, StringWithSurroundingSpacesGreaterThanNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, " 5.25 ", 5.25);
+}
+
+TEST_F(LLVMGreaterThanTest, StringWithSurroundingSpacesGreaterThanNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, " 5.25 ", 5.25);
+}
+
+TEST_F(LLVMGreaterThanTest, NumberGreaterThanDifferentString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 5.25, "5.26");
+}
+
+TEST_F(LLVMGreaterThanTest, NumberGreaterThanDifferentString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 5.25, "5.26");
+}
+
+TEST_F(LLVMGreaterThanTest, DifferentStringGreaterThanNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "5.26", 5.25);
+}
+
+TEST_F(LLVMGreaterThanTest, DifferentStringGreaterThanNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "5.26", 5.25);
+}
+
+TEST_F(LLVMGreaterThanTest, DifferentStringNumbers)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "5.25", "5.26");
+}
+
+TEST_F(LLVMGreaterThanTest, DifferentStringNumbers_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "5.25", "5.26");
+}
+
+TEST_F(LLVMGreaterThanTest, NumberGreaterThanStringWithTrailingSpaces)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 5, "5  ");
+}
+
+TEST_F(LLVMGreaterThanTest, NumberGreaterThanStringWithTrailingSpaces_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 5, "5  ");
+}
+
+TEST_F(LLVMGreaterThanTest, StringWithTrailingSpacesGreaterThanNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "5  ", 5);
+}
+
+TEST_F(LLVMGreaterThanTest, StringWithTrailingSpacesGreaterThanNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "5  ", 5);
+}
+
+TEST_F(LLVMGreaterThanTest, ZeroGreaterThanOneString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 0, "1");
+}
+
+TEST_F(LLVMGreaterThanTest, ZeroGreaterThanOneString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 0, "1");
+}
+
+TEST_F(LLVMGreaterThanTest, OneStringGreaterThanZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "1", 0);
+}
+
+TEST_F(LLVMGreaterThanTest, OneStringGreaterThanZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "1", 0);
+}
+
+TEST_F(LLVMGreaterThanTest, ZeroGreaterThanTestString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 0, "test");
+}
+
+TEST_F(LLVMGreaterThanTest, ZeroGreaterThanTestString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 0, "test");
+}
+
+TEST_F(LLVMGreaterThanTest, TestStringGreaterThanZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "test", 0);
+}
+
+TEST_F(LLVMGreaterThanTest, TestStringGreaterThanZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "test", 0);
+}
+
+TEST_F(LLVMGreaterThanTest, NumberGreaterThanAbcString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 55, "abc");
+}
+
+TEST_F(LLVMGreaterThanTest, NumberGreaterThanAbcString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 55, "abc");
+}
+
+TEST_F(LLVMGreaterThanTest, AbcStringGreaterThanNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "abc", 55);
+}
+
+TEST_F(LLVMGreaterThanTest, AbcStringGreaterThanNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "abc", 55);
+}
+
+TEST_F(LLVMGreaterThanTest, InfinityGreaterThanInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, InfinityGreaterThanInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, NegativeInfinityGreaterThanNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, NegativeInfinityGreaterThanNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, NaNGreaterThanNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "NaN", "NaN");
+}
+
+TEST_F(LLVMGreaterThanTest, NaNGreaterThanNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "NaN", "NaN");
+}
+
+TEST_F(LLVMGreaterThanTest, InfinityGreaterThanNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, InfinityGreaterThanNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, NegativeInfinityGreaterThanInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, NegativeInfinityGreaterThanInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, InfinityGreaterThanNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "Infinity", "NaN");
+}
+
+TEST_F(LLVMGreaterThanTest, InfinityGreaterThanNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "Infinity", "NaN");
+}
+
+TEST_F(LLVMGreaterThanTest, NaNGreaterThanInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "NaN", "Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, NaNGreaterThanInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "NaN", "Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, NegativeInfinityGreaterThanNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "-Infinity", "NaN");
+}
+
+TEST_F(LLVMGreaterThanTest, NegativeInfinityGreaterThanNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "-Infinity", "NaN");
+}
+
+TEST_F(LLVMGreaterThanTest, NaNGreaterThanNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "NaN", "-Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, NaNGreaterThanNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "NaN", "-Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, NumberGreaterThanInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 5, "Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, NumberGreaterThanInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 5, "Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, InfinityGreaterThanNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "Infinity", 5);
+}
+
+TEST_F(LLVMGreaterThanTest, InfinityGreaterThanNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "Infinity", 5);
+}
+
+TEST_F(LLVMGreaterThanTest, NumberGreaterThanNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 5, "-Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, NumberGreaterThanNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 5, "-Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, NegativeInfinityGreaterThanNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "-Infinity", 5);
+}
+
+TEST_F(LLVMGreaterThanTest, NegativeInfinityGreaterThanNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "-Infinity", 5);
+}
+
+TEST_F(LLVMGreaterThanTest, NumberGreaterThanNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 5, "NaN");
+}
+
+TEST_F(LLVMGreaterThanTest, NumberGreaterThanNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 5, "NaN");
+}
+
+TEST_F(LLVMGreaterThanTest, NaNGreaterThanNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "NaN", 5);
+}
+
+TEST_F(LLVMGreaterThanTest, NaNGreaterThanNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "NaN", 5);
+}
+
+TEST_F(LLVMGreaterThanTest, ZeroGreaterThanNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 0, "NaN");
+}
+
+TEST_F(LLVMGreaterThanTest, ZeroGreaterThanNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 0, "NaN");
+}
+
+TEST_F(LLVMGreaterThanTest, NaNGreaterThanZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "NaN", 0);
+}
+
+TEST_F(LLVMGreaterThanTest, NaNGreaterThanZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "NaN", 0);
+}
+
+TEST_F(LLVMGreaterThanTest, TrueBooleanWithTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, true, "true");
+}
+
+TEST_F(LLVMGreaterThanTest, TrueBooleanWithTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, true, "true");
+}
+
+TEST_F(LLVMGreaterThanTest, TrueStringWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "true", true);
+}
+
+TEST_F(LLVMGreaterThanTest, TrueStringWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "true", true);
+}
+
+TEST_F(LLVMGreaterThanTest, FalseBooleanWithFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, false, "false");
+}
+
+TEST_F(LLVMGreaterThanTest, FalseBooleanWithFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, false, "false");
+}
+
+TEST_F(LLVMGreaterThanTest, FalseStringWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "false", false);
+}
+
+TEST_F(LLVMGreaterThanTest, FalseStringWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "false", false);
+}
+
+TEST_F(LLVMGreaterThanTest, FalseBooleanWithTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, false, "true");
+}
+
+TEST_F(LLVMGreaterThanTest, FalseBooleanWithTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, false, "true");
+}
+
+TEST_F(LLVMGreaterThanTest, TrueStringWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "true", false);
+}
+
+TEST_F(LLVMGreaterThanTest, TrueStringWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "true", false);
+}
+
+TEST_F(LLVMGreaterThanTest, TrueBooleanWithFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, true, "false");
+}
+
+TEST_F(LLVMGreaterThanTest, TrueBooleanWithFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, true, "false");
+}
+
+TEST_F(LLVMGreaterThanTest, FalseStringWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "false", true);
+}
+
+TEST_F(LLVMGreaterThanTest, FalseStringWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "false", true);
+}
+
+TEST_F(LLVMGreaterThanTest, TrueBooleanWithUppercaseTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, true, "TRUE");
+}
+
+TEST_F(LLVMGreaterThanTest, TrueBooleanWithUppercaseTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, true, "TRUE");
+}
+
+TEST_F(LLVMGreaterThanTest, UppercaseTrueStringWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "TRUE", true);
+}
+
+TEST_F(LLVMGreaterThanTest, UppercaseTrueStringWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "TRUE", true);
+}
+
+TEST_F(LLVMGreaterThanTest, FalseBooleanWithUppercaseFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, false, "FALSE");
+}
+
+TEST_F(LLVMGreaterThanTest, FalseBooleanWithUppercaseFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, false, "FALSE");
+}
+
+TEST_F(LLVMGreaterThanTest, UppercaseFalseStringWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "FALSE", false);
+}
+
+TEST_F(LLVMGreaterThanTest, UppercaseFalseStringWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "FALSE", false);
+}
+
+TEST_F(LLVMGreaterThanTest, TrueBooleanWithZeroPaddedOne)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, true, "00001");
+}
+
+TEST_F(LLVMGreaterThanTest, TrueBooleanWithZeroPaddedOne_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, true, "00001");
+}
+
+TEST_F(LLVMGreaterThanTest, ZeroPaddedOneWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "00001", true);
+}
+
+TEST_F(LLVMGreaterThanTest, ZeroPaddedOneWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "00001", true);
+}
+
+TEST_F(LLVMGreaterThanTest, TrueBooleanWithZeroPaddedZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, true, "00000");
+}
+
+TEST_F(LLVMGreaterThanTest, TrueBooleanWithZeroPaddedZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, true, "00000");
+}
+
+TEST_F(LLVMGreaterThanTest, ZeroPaddedZeroWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "00000", true);
+}
+
+TEST_F(LLVMGreaterThanTest, ZeroPaddedZeroWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "00000", true);
+}
+
+TEST_F(LLVMGreaterThanTest, FalseBooleanWithZeroPaddedZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, false, "00000");
+}
+
+TEST_F(LLVMGreaterThanTest, FalseBooleanWithZeroPaddedZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, false, "00000");
+}
+
+TEST_F(LLVMGreaterThanTest, ZeroPaddedZeroWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "00000", false);
+}
+
+TEST_F(LLVMGreaterThanTest, ZeroPaddedZeroWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "00000", false);
+}
+
+TEST_F(LLVMGreaterThanTest, TrueStringWithOne)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "true", 1);
+}
+
+TEST_F(LLVMGreaterThanTest, TrueStringWithOne_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "true", 1);
+}
+
+TEST_F(LLVMGreaterThanTest, OneWithTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 1, "true");
+}
+
+TEST_F(LLVMGreaterThanTest, OneWithTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 1, "true");
+}
+
+TEST_F(LLVMGreaterThanTest, TrueStringWithZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "true", 0);
+}
+
+TEST_F(LLVMGreaterThanTest, TrueStringWithZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "true", 0);
+}
+
+TEST_F(LLVMGreaterThanTest, ZeroWithTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 0, "true");
+}
+
+TEST_F(LLVMGreaterThanTest, ZeroWithTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 0, "true");
+}
+
+TEST_F(LLVMGreaterThanTest, FalseStringWithZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "false", 0);
+}
+
+TEST_F(LLVMGreaterThanTest, FalseStringWithZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "false", 0);
+}
+
+TEST_F(LLVMGreaterThanTest, ZeroWithFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 0, "false");
+}
+
+TEST_F(LLVMGreaterThanTest, ZeroWithFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 0, "false");
+}
+
+TEST_F(LLVMGreaterThanTest, FalseStringWithOne)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "false", 1);
+}
+
+TEST_F(LLVMGreaterThanTest, FalseStringWithOne_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "false", 1);
+}
+
+TEST_F(LLVMGreaterThanTest, OneWithFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, 1, "false");
+}
+
+TEST_F(LLVMGreaterThanTest, OneWithFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, 1, "false");
+}
+
+TEST_F(LLVMGreaterThanTest, TrueStringWithUppercaseTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "true", "TRUE");
+}
+
+TEST_F(LLVMGreaterThanTest, TrueStringWithUppercaseTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "true", "TRUE");
+}
+
+TEST_F(LLVMGreaterThanTest, TrueStringWithUppercaseFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "true", "FALSE");
+}
+
+TEST_F(LLVMGreaterThanTest, TrueStringWithUppercaseFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "true", "FALSE");
+}
+
+TEST_F(LLVMGreaterThanTest, FalseStringWithUppercaseFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "false", "FALSE");
+}
+
+TEST_F(LLVMGreaterThanTest, FalseStringWithUppercaseFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "false", "FALSE");
+}
+
+TEST_F(LLVMGreaterThanTest, FalseStringWithUppercaseTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "false", "TRUE");
+}
+
+TEST_F(LLVMGreaterThanTest, FalseStringWithUppercaseTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "false", "TRUE");
+}
+
+TEST_F(LLVMGreaterThanTest, TrueBooleanWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, true, "Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, TrueBooleanWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, true, "Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, InfinityWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "Infinity", true);
+}
+
+TEST_F(LLVMGreaterThanTest, InfinityWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "Infinity", true);
+}
+
+TEST_F(LLVMGreaterThanTest, TrueBooleanWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, true, "-Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, TrueBooleanWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, true, "-Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, NegativeInfinityWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "-Infinity", true);
+}
+
+TEST_F(LLVMGreaterThanTest, NegativeInfinityWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "-Infinity", true);
+}
+
+TEST_F(LLVMGreaterThanTest, TrueBooleanWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, true, "NaN");
+}
+
+TEST_F(LLVMGreaterThanTest, TrueBooleanWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, true, "NaN");
+}
+
+TEST_F(LLVMGreaterThanTest, NaNWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "NaN", true);
+}
+
+TEST_F(LLVMGreaterThanTest, NaNWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "NaN", true);
+}
+
+TEST_F(LLVMGreaterThanTest, FalseBooleanWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, false, "Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, FalseBooleanWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, false, "Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, InfinityWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "Infinity", false);
+}
+
+TEST_F(LLVMGreaterThanTest, InfinityWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "Infinity", false);
+}
+
+TEST_F(LLVMGreaterThanTest, FalseBooleanWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, false, "-Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, FalseBooleanWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, false, "-Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, NegativeInfinityWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "-Infinity", false);
+}
+
+TEST_F(LLVMGreaterThanTest, NegativeInfinityWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "-Infinity", false);
+}
+
+TEST_F(LLVMGreaterThanTest, FalseBooleanWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, false, "NaN");
+}
+
+TEST_F(LLVMGreaterThanTest, FalseBooleanWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, false, "NaN");
+}
+
+TEST_F(LLVMGreaterThanTest, NaNWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "NaN", false);
+}
+
+TEST_F(LLVMGreaterThanTest, NaNWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "NaN", false);
+}
+
+TEST_F(LLVMGreaterThanTest, InfinityStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, InfinityStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, InfinityStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, InfinityStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, InfinityStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "Infinity", "NaN");
+}
+
+TEST_F(LLVMGreaterThanTest, InfinityStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "Infinity", "NaN");
+}
+
+TEST_F(LLVMGreaterThanTest, LowercaseInfinityStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "infinity", "Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, LowercaseInfinityStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "infinity", "Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, LowercaseInfinityStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "infinity", "-Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, LowercaseInfinityStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "infinity", "-Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, LowercaseInfinityStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "infinity", "NaN");
+}
+
+TEST_F(LLVMGreaterThanTest, LowercaseInfinityStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "infinity", "NaN");
+}
+
+TEST_F(LLVMGreaterThanTest, NegativeInfinityStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, NegativeInfinityStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, NegativeInfinityStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, NegativeInfinityStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, NegativeInfinityStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "-Infinity", "NaN");
+}
+
+TEST_F(LLVMGreaterThanTest, NegativeInfinityStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "-Infinity", "NaN");
+}
+
+TEST_F(LLVMGreaterThanTest, LowercaseNegativeInfinityStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "-infinity", "Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, LowercaseNegativeInfinityStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "-infinity", "Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, LowercaseNegativeInfinityStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "-infinity", "-Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, LowercaseNegativeInfinityStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "-infinity", "-Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, LowercaseNegativeInfinityStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "-infinity", "NaN");
+}
+
+TEST_F(LLVMGreaterThanTest, LowercaseNegativeInfinityStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "-infinity", "NaN");
+}
+
+TEST_F(LLVMGreaterThanTest, NaNStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "NaN", "Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, NaNStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "NaN", "Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, NaNStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "NaN", "-Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, NaNStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "NaN", "-Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, NaNStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "NaN", "NaN");
+}
+
+TEST_F(LLVMGreaterThanTest, NaNStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "NaN", "NaN");
+}
+
+TEST_F(LLVMGreaterThanTest, LowercaseNaNStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "nan", "Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, LowercaseNaNStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "nan", "Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, LowercaseNaNStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "nan", "-Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, LowercaseNaNStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "nan", "-Infinity");
+}
+
+TEST_F(LLVMGreaterThanTest, LowercaseNaNStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "nan", "NaN");
+}
+
+TEST_F(LLVMGreaterThanTest, LowercaseNaNStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "nan", "NaN");
+}
+
+TEST_F(LLVMGreaterThanTest, InfinityWithStringAbc)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "Infinity", "abc");
+}
+
+TEST_F(LLVMGreaterThanTest, InfinityWithStringAbc_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "Infinity", "abc");
+}
+
+TEST_F(LLVMGreaterThanTest, InfinityWithStringSpace)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "Infinity", " ");
+}
+
+TEST_F(LLVMGreaterThanTest, InfinityWithStringSpace_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "Infinity", " ");
+}
+
+TEST_F(LLVMGreaterThanTest, InfinityWithEmptyString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "Infinity", "");
+}
+
+TEST_F(LLVMGreaterThanTest, InfinityWithEmptyString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "Infinity", "");
+}
+
+TEST_F(LLVMGreaterThanTest, InfinityWithZeroString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "Infinity", "0");
+}
+
+TEST_F(LLVMGreaterThanTest, InfinityWithZeroString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "Infinity", "0");
+}
+
+TEST_F(LLVMGreaterThanTest, NegativeInfinityWithStringAbc)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "-Infinity", "abc");
+}
+
+TEST_F(LLVMGreaterThanTest, NegativeInfinityWithStringAbc_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "-Infinity", "abc");
+}
+
+TEST_F(LLVMGreaterThanTest, NegativeInfinityWithStringSpace)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "-Infinity", " ");
+}
+
+TEST_F(LLVMGreaterThanTest, NegativeInfinityWithStringSpace_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "-Infinity", " ");
+}
+
+TEST_F(LLVMGreaterThanTest, NegativeInfinityWithEmptyString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "-Infinity", "");
+}
+
+TEST_F(LLVMGreaterThanTest, NegativeInfinityWithEmptyString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "-Infinity", "");
+}
+
+TEST_F(LLVMGreaterThanTest, NegativeInfinityWithZeroString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "-Infinity", "0");
+}
+
+TEST_F(LLVMGreaterThanTest, NegativeInfinityWithZeroString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "-Infinity", "0");
+}
+
+TEST_F(LLVMGreaterThanTest, NaNWithStringAbc)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "NaN", "abc");
+}
+
+TEST_F(LLVMGreaterThanTest, NaNWithStringAbc_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "NaN", "abc");
+}
+
+TEST_F(LLVMGreaterThanTest, NaNWithStringSpace)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "NaN", " ");
+}
+
+TEST_F(LLVMGreaterThanTest, NaNWithStringSpace_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "NaN", " ");
+}
+
+TEST_F(LLVMGreaterThanTest, NaNWithEmptyString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "NaN", "");
+}
+
+TEST_F(LLVMGreaterThanTest, NaNWithEmptyString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "NaN", "");
+}
+
+TEST_F(LLVMGreaterThanTest, NaNWithZeroString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, false, "NaN", "0");
+}
+
+TEST_F(LLVMGreaterThanTest, NaNWithZeroString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpGT, true, "NaN", "0");
+}
diff --git a/test/llvm/operators/less_than_test.cpp b/test/llvm/operators/less_than_test.cpp
new file mode 100644
index 00000000..fcfcadc2
--- /dev/null
+++ b/test/llvm/operators/less_than_test.cpp
@@ -0,0 +1,1340 @@
+#include <gtest/gtest.h>
+#include <scratchcpp/value.h>
+
+#include "llvmtestutils.h"
+
+class LLVMLessThanTest : public testing::Test
+{
+    public:
+        LLVMTestUtils m_utils;
+};
+
+TEST_F(LLVMLessThanTest, SameIntegers)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 10, 10);
+}
+
+TEST_F(LLVMLessThanTest, SameIntegers_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 10, 10);
+}
+
+TEST_F(LLVMLessThanTest, FirstGreaterInteger)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 10, 8);
+}
+
+TEST_F(LLVMLessThanTest, FirstGreaterInteger_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 10, 8);
+}
+
+TEST_F(LLVMLessThanTest, SecondGreaterInteger)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 8, 10);
+}
+
+TEST_F(LLVMLessThanTest, SecondGreaterInteger_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 8, 10);
+}
+
+TEST_F(LLVMLessThanTest, SameDecimals)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, -4.25, -4.25);
+}
+
+TEST_F(LLVMLessThanTest, SameDecimals_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, -4.25, -4.25);
+}
+
+TEST_F(LLVMLessThanTest, FirstGreaterDecimal)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, -4.25, 5.312);
+}
+
+TEST_F(LLVMLessThanTest, FirstGreaterDecimal_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, -4.25, 5.312);
+}
+
+TEST_F(LLVMLessThanTest, SecondGreaterDecimal)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 5.312, -4.25);
+}
+
+TEST_F(LLVMLessThanTest, SecondGreaterDecimal_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 5.312, -4.25);
+}
+
+TEST_F(LLVMLessThanTest, SameBooleans)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, true, true);
+}
+
+TEST_F(LLVMLessThanTest, SameBooleans_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, true, true);
+}
+
+TEST_F(LLVMLessThanTest, TrueGreaterThanFalse)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, true, false);
+}
+
+TEST_F(LLVMLessThanTest, TrueGreaterThanFalse_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, true, false);
+}
+
+TEST_F(LLVMLessThanTest, FalseGreaterThanTrue)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, false, true);
+}
+
+TEST_F(LLVMLessThanTest, FalseGreaterThanTrue_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, false, true);
+}
+
+TEST_F(LLVMLessThanTest, NumberGreaterThanTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 1, true);
+}
+
+TEST_F(LLVMLessThanTest, NumberGreaterThanTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 1, true);
+}
+
+TEST_F(LLVMLessThanTest, NumberGreaterThanFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 1, false);
+}
+
+TEST_F(LLVMLessThanTest, NumberGreaterThanFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 1, false);
+}
+
+TEST_F(LLVMLessThanTest, SameStrings)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "abC def", "abC def");
+}
+
+TEST_F(LLVMLessThanTest, SameStrings_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "abC def", "abC def");
+}
+
+TEST_F(LLVMLessThanTest, StringsCaseDifferent)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "abC def", "abc dEf");
+}
+
+TEST_F(LLVMLessThanTest, StringsCaseDifferent_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "abC def", "abc dEf");
+}
+
+TEST_F(LLVMLessThanTest, FirstStringGreater)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "abC def", "ghi Jkl");
+}
+
+TEST_F(LLVMLessThanTest, FirstStringGreater_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "abC def", "ghi Jkl");
+}
+
+TEST_F(LLVMLessThanTest, SecondStringGreater)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "ghi Jkl", "abC def");
+}
+
+TEST_F(LLVMLessThanTest, SecondStringGreater_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "ghi Jkl", "abC def");
+}
+
+TEST_F(LLVMLessThanTest, StringsLengthComparison)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "abC def", "hello world");
+}
+
+TEST_F(LLVMLessThanTest, StringsLengthComparison_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "abC def", "hello world");
+}
+
+TEST_F(LLVMLessThanTest, SpaceGreaterThanEmpty)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, " ", "");
+}
+
+TEST_F(LLVMLessThanTest, SpaceGreaterThanEmpty_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, " ", "");
+}
+
+TEST_F(LLVMLessThanTest, SpaceGreaterThanZeroString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, " ", "0");
+}
+
+TEST_F(LLVMLessThanTest, SpaceGreaterThanZeroString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, " ", "0");
+}
+
+TEST_F(LLVMLessThanTest, SpaceGreaterThanZeroNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, " ", 0);
+}
+
+TEST_F(LLVMLessThanTest, SpaceGreaterThanZeroNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, " ", 0);
+}
+
+TEST_F(LLVMLessThanTest, ZeroNumberGreaterThanSpace)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 0, " ");
+}
+
+TEST_F(LLVMLessThanTest, ZeroNumberGreaterThanSpace_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 0, " ");
+}
+
+TEST_F(LLVMLessThanTest, EmptyGreaterThanZeroString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "", "0");
+}
+
+TEST_F(LLVMLessThanTest, EmptyGreaterThanZeroString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "", "0");
+}
+
+TEST_F(LLVMLessThanTest, EmptyGreaterThanZeroNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "", 0);
+}
+
+TEST_F(LLVMLessThanTest, EmptyGreaterThanZeroNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "", 0);
+}
+
+TEST_F(LLVMLessThanTest, ZeroNumberGreaterThanEmpty)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 0, "");
+}
+
+TEST_F(LLVMLessThanTest, ZeroNumberGreaterThanEmpty_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 0, "");
+}
+
+TEST_F(LLVMLessThanTest, ZeroStringGreaterThanZeroNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "0", 0);
+}
+
+TEST_F(LLVMLessThanTest, ZeroStringGreaterThanZeroNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "0", 0);
+}
+
+TEST_F(LLVMLessThanTest, ZeroNumberGreaterThanZeroString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 0, "0");
+}
+
+TEST_F(LLVMLessThanTest, ZeroNumberGreaterThanZeroString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 0, "0");
+}
+
+TEST_F(LLVMLessThanTest, NumberGreaterThanExactString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 5.25, "5.25");
+}
+
+TEST_F(LLVMLessThanTest, NumberGreaterThanExactString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 5.25, "5.25");
+}
+
+TEST_F(LLVMLessThanTest, ExactStringGreaterThanNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "5.25", 5.25);
+}
+
+TEST_F(LLVMLessThanTest, ExactStringGreaterThanNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "5.25", 5.25);
+}
+
+TEST_F(LLVMLessThanTest, NumberGreaterThanStringWithLeadingSpace)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 5.25, " 5.25");
+}
+
+TEST_F(LLVMLessThanTest, NumberGreaterThanStringWithLeadingSpace_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 5.25, " 5.25");
+}
+
+TEST_F(LLVMLessThanTest, StringWithLeadingSpaceGreaterThanNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, " 5.25", 5.25);
+}
+
+TEST_F(LLVMLessThanTest, StringWithLeadingSpaceGreaterThanNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, " 5.25", 5.25);
+}
+
+TEST_F(LLVMLessThanTest, NumberGreaterThanStringWithTrailingSpace)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 5.25, "5.25 ");
+}
+
+TEST_F(LLVMLessThanTest, NumberGreaterThanStringWithTrailingSpace_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 5.25, "5.25 ");
+}
+
+TEST_F(LLVMLessThanTest, StringWithTrailingSpaceGreaterThanNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "5.25 ", 5.25);
+}
+
+TEST_F(LLVMLessThanTest, StringWithTrailingSpaceGreaterThanNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "5.25 ", 5.25);
+}
+
+TEST_F(LLVMLessThanTest, NumberGreaterThanStringWithSurroundingSpaces)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 5.25, " 5.25 ");
+}
+
+TEST_F(LLVMLessThanTest, NumberGreaterThanStringWithSurroundingSpaces_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 5.25, " 5.25 ");
+}
+
+TEST_F(LLVMLessThanTest, StringWithSurroundingSpacesGreaterThanNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, " 5.25 ", 5.25);
+}
+
+TEST_F(LLVMLessThanTest, StringWithSurroundingSpacesGreaterThanNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, " 5.25 ", 5.25);
+}
+
+TEST_F(LLVMLessThanTest, NumberGreaterThanDifferentString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 5.25, "5.26");
+}
+
+TEST_F(LLVMLessThanTest, NumberGreaterThanDifferentString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 5.25, "5.26");
+}
+
+TEST_F(LLVMLessThanTest, DifferentStringGreaterThanNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "5.26", 5.25);
+}
+
+TEST_F(LLVMLessThanTest, DifferentStringGreaterThanNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "5.26", 5.25);
+}
+
+TEST_F(LLVMLessThanTest, DifferentStringNumbers)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "5.25", "5.26");
+}
+
+TEST_F(LLVMLessThanTest, DifferentStringNumbers_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "5.25", "5.26");
+}
+
+TEST_F(LLVMLessThanTest, NumberGreaterThanStringWithTrailingSpaces)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 5, "5  ");
+}
+
+TEST_F(LLVMLessThanTest, NumberGreaterThanStringWithTrailingSpaces_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 5, "5  ");
+}
+
+TEST_F(LLVMLessThanTest, StringWithTrailingSpacesGreaterThanNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "5  ", 5);
+}
+
+TEST_F(LLVMLessThanTest, StringWithTrailingSpacesGreaterThanNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "5  ", 5);
+}
+
+TEST_F(LLVMLessThanTest, ZeroGreaterThanOneString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 0, "1");
+}
+
+TEST_F(LLVMLessThanTest, ZeroGreaterThanOneString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 0, "1");
+}
+
+TEST_F(LLVMLessThanTest, OneStringGreaterThanZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "1", 0);
+}
+
+TEST_F(LLVMLessThanTest, OneStringGreaterThanZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "1", 0);
+}
+
+TEST_F(LLVMLessThanTest, ZeroGreaterThanTestString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 0, "test");
+}
+
+TEST_F(LLVMLessThanTest, ZeroGreaterThanTestString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 0, "test");
+}
+
+TEST_F(LLVMLessThanTest, TestStringGreaterThanZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "test", 0);
+}
+
+TEST_F(LLVMLessThanTest, TestStringGreaterThanZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "test", 0);
+}
+
+TEST_F(LLVMLessThanTest, NumberGreaterThanAbcString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 55, "abc");
+}
+
+TEST_F(LLVMLessThanTest, NumberGreaterThanAbcString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 55, "abc");
+}
+
+TEST_F(LLVMLessThanTest, AbcStringGreaterThanNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "abc", 55);
+}
+
+TEST_F(LLVMLessThanTest, AbcStringGreaterThanNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "abc", 55);
+}
+
+TEST_F(LLVMLessThanTest, InfinityGreaterThanInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMLessThanTest, InfinityGreaterThanInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMLessThanTest, NegativeInfinityGreaterThanNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMLessThanTest, NegativeInfinityGreaterThanNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMLessThanTest, NaNGreaterThanNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "NaN", "NaN");
+}
+
+TEST_F(LLVMLessThanTest, NaNGreaterThanNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "NaN", "NaN");
+}
+
+TEST_F(LLVMLessThanTest, InfinityGreaterThanNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMLessThanTest, InfinityGreaterThanNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMLessThanTest, NegativeInfinityGreaterThanInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMLessThanTest, NegativeInfinityGreaterThanInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMLessThanTest, InfinityGreaterThanNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "Infinity", "NaN");
+}
+
+TEST_F(LLVMLessThanTest, InfinityGreaterThanNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "Infinity", "NaN");
+}
+
+TEST_F(LLVMLessThanTest, NaNGreaterThanInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "NaN", "Infinity");
+}
+
+TEST_F(LLVMLessThanTest, NaNGreaterThanInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "NaN", "Infinity");
+}
+
+TEST_F(LLVMLessThanTest, NegativeInfinityGreaterThanNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "-Infinity", "NaN");
+}
+
+TEST_F(LLVMLessThanTest, NegativeInfinityGreaterThanNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "-Infinity", "NaN");
+}
+
+TEST_F(LLVMLessThanTest, NaNGreaterThanNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "NaN", "-Infinity");
+}
+
+TEST_F(LLVMLessThanTest, NaNGreaterThanNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "NaN", "-Infinity");
+}
+
+TEST_F(LLVMLessThanTest, NumberGreaterThanInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 5, "Infinity");
+}
+
+TEST_F(LLVMLessThanTest, NumberGreaterThanInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 5, "Infinity");
+}
+
+TEST_F(LLVMLessThanTest, InfinityGreaterThanNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "Infinity", 5);
+}
+
+TEST_F(LLVMLessThanTest, InfinityGreaterThanNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "Infinity", 5);
+}
+
+TEST_F(LLVMLessThanTest, NumberGreaterThanNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 5, "-Infinity");
+}
+
+TEST_F(LLVMLessThanTest, NumberGreaterThanNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 5, "-Infinity");
+}
+
+TEST_F(LLVMLessThanTest, NegativeInfinityGreaterThanNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "-Infinity", 5);
+}
+
+TEST_F(LLVMLessThanTest, NegativeInfinityGreaterThanNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "-Infinity", 5);
+}
+
+TEST_F(LLVMLessThanTest, NumberGreaterThanNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 5, "NaN");
+}
+
+TEST_F(LLVMLessThanTest, NumberGreaterThanNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 5, "NaN");
+}
+
+TEST_F(LLVMLessThanTest, NaNGreaterThanNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "NaN", 5);
+}
+
+TEST_F(LLVMLessThanTest, NaNGreaterThanNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "NaN", 5);
+}
+
+TEST_F(LLVMLessThanTest, ZeroGreaterThanNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 0, "NaN");
+}
+
+TEST_F(LLVMLessThanTest, ZeroGreaterThanNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 0, "NaN");
+}
+
+TEST_F(LLVMLessThanTest, NaNGreaterThanZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "NaN", 0);
+}
+
+TEST_F(LLVMLessThanTest, NaNGreaterThanZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "NaN", 0);
+}
+
+TEST_F(LLVMLessThanTest, TrueBooleanWithTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, true, "true");
+}
+
+TEST_F(LLVMLessThanTest, TrueBooleanWithTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, true, "true");
+}
+
+TEST_F(LLVMLessThanTest, TrueStringWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "true", true);
+}
+
+TEST_F(LLVMLessThanTest, TrueStringWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "true", true);
+}
+
+TEST_F(LLVMLessThanTest, FalseBooleanWithFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, false, "false");
+}
+
+TEST_F(LLVMLessThanTest, FalseBooleanWithFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, false, "false");
+}
+
+TEST_F(LLVMLessThanTest, FalseStringWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "false", false);
+}
+
+TEST_F(LLVMLessThanTest, FalseStringWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "false", false);
+}
+
+TEST_F(LLVMLessThanTest, FalseBooleanWithTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, false, "true");
+}
+
+TEST_F(LLVMLessThanTest, FalseBooleanWithTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, false, "true");
+}
+
+TEST_F(LLVMLessThanTest, TrueStringWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "true", false);
+}
+
+TEST_F(LLVMLessThanTest, TrueStringWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "true", false);
+}
+
+TEST_F(LLVMLessThanTest, TrueBooleanWithFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, true, "false");
+}
+
+TEST_F(LLVMLessThanTest, TrueBooleanWithFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, true, "false");
+}
+
+TEST_F(LLVMLessThanTest, FalseStringWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "false", true);
+}
+
+TEST_F(LLVMLessThanTest, FalseStringWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "false", true);
+}
+
+TEST_F(LLVMLessThanTest, TrueBooleanWithUppercaseTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, true, "TRUE");
+}
+
+TEST_F(LLVMLessThanTest, TrueBooleanWithUppercaseTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, true, "TRUE");
+}
+
+TEST_F(LLVMLessThanTest, UppercaseTrueStringWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "TRUE", true);
+}
+
+TEST_F(LLVMLessThanTest, UppercaseTrueStringWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "TRUE", true);
+}
+
+TEST_F(LLVMLessThanTest, FalseBooleanWithUppercaseFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, false, "FALSE");
+}
+
+TEST_F(LLVMLessThanTest, FalseBooleanWithUppercaseFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, false, "FALSE");
+}
+
+TEST_F(LLVMLessThanTest, UppercaseFalseStringWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "FALSE", false);
+}
+
+TEST_F(LLVMLessThanTest, UppercaseFalseStringWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "FALSE", false);
+}
+
+TEST_F(LLVMLessThanTest, TrueBooleanWithZeroPaddedOne)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, true, "00001");
+}
+
+TEST_F(LLVMLessThanTest, TrueBooleanWithZeroPaddedOne_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, true, "00001");
+}
+
+TEST_F(LLVMLessThanTest, ZeroPaddedOneWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "00001", true);
+}
+
+TEST_F(LLVMLessThanTest, ZeroPaddedOneWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "00001", true);
+}
+
+TEST_F(LLVMLessThanTest, TrueBooleanWithZeroPaddedZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, true, "00000");
+}
+
+TEST_F(LLVMLessThanTest, TrueBooleanWithZeroPaddedZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, true, "00000");
+}
+
+TEST_F(LLVMLessThanTest, ZeroPaddedZeroWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "00000", true);
+}
+
+TEST_F(LLVMLessThanTest, ZeroPaddedZeroWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "00000", true);
+}
+
+TEST_F(LLVMLessThanTest, FalseBooleanWithZeroPaddedZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, false, "00000");
+}
+
+TEST_F(LLVMLessThanTest, FalseBooleanWithZeroPaddedZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, false, "00000");
+}
+
+TEST_F(LLVMLessThanTest, ZeroPaddedZeroWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "00000", false);
+}
+
+TEST_F(LLVMLessThanTest, ZeroPaddedZeroWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "00000", false);
+}
+
+TEST_F(LLVMLessThanTest, TrueStringWithOne)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "true", 1);
+}
+
+TEST_F(LLVMLessThanTest, TrueStringWithOne_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "true", 1);
+}
+
+TEST_F(LLVMLessThanTest, OneWithTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 1, "true");
+}
+
+TEST_F(LLVMLessThanTest, OneWithTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 1, "true");
+}
+
+TEST_F(LLVMLessThanTest, TrueStringWithZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "true", 0);
+}
+
+TEST_F(LLVMLessThanTest, TrueStringWithZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "true", 0);
+}
+
+TEST_F(LLVMLessThanTest, ZeroWithTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 0, "true");
+}
+
+TEST_F(LLVMLessThanTest, ZeroWithTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 0, "true");
+}
+
+TEST_F(LLVMLessThanTest, FalseStringWithZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "false", 0);
+}
+
+TEST_F(LLVMLessThanTest, FalseStringWithZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "false", 0);
+}
+
+TEST_F(LLVMLessThanTest, ZeroWithFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 0, "false");
+}
+
+TEST_F(LLVMLessThanTest, ZeroWithFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 0, "false");
+}
+
+TEST_F(LLVMLessThanTest, FalseStringWithOne)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "false", 1);
+}
+
+TEST_F(LLVMLessThanTest, FalseStringWithOne_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "false", 1);
+}
+
+TEST_F(LLVMLessThanTest, OneWithFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, 1, "false");
+}
+
+TEST_F(LLVMLessThanTest, OneWithFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, 1, "false");
+}
+
+TEST_F(LLVMLessThanTest, TrueStringWithUppercaseTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "true", "TRUE");
+}
+
+TEST_F(LLVMLessThanTest, TrueStringWithUppercaseTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "true", "TRUE");
+}
+
+TEST_F(LLVMLessThanTest, TrueStringWithUppercaseFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "true", "FALSE");
+}
+
+TEST_F(LLVMLessThanTest, TrueStringWithUppercaseFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "true", "FALSE");
+}
+
+TEST_F(LLVMLessThanTest, FalseStringWithUppercaseFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "false", "FALSE");
+}
+
+TEST_F(LLVMLessThanTest, FalseStringWithUppercaseFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "false", "FALSE");
+}
+
+TEST_F(LLVMLessThanTest, FalseStringWithUppercaseTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "false", "TRUE");
+}
+
+TEST_F(LLVMLessThanTest, FalseStringWithUppercaseTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "false", "TRUE");
+}
+
+TEST_F(LLVMLessThanTest, TrueBooleanWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, true, "Infinity");
+}
+
+TEST_F(LLVMLessThanTest, TrueBooleanWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, true, "Infinity");
+}
+
+TEST_F(LLVMLessThanTest, InfinityWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "Infinity", true);
+}
+
+TEST_F(LLVMLessThanTest, InfinityWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "Infinity", true);
+}
+
+TEST_F(LLVMLessThanTest, TrueBooleanWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, true, "-Infinity");
+}
+
+TEST_F(LLVMLessThanTest, TrueBooleanWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, true, "-Infinity");
+}
+
+TEST_F(LLVMLessThanTest, NegativeInfinityWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "-Infinity", true);
+}
+
+TEST_F(LLVMLessThanTest, NegativeInfinityWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "-Infinity", true);
+}
+
+TEST_F(LLVMLessThanTest, TrueBooleanWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, true, "NaN");
+}
+
+TEST_F(LLVMLessThanTest, TrueBooleanWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, true, "NaN");
+}
+
+TEST_F(LLVMLessThanTest, NaNWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "NaN", true);
+}
+
+TEST_F(LLVMLessThanTest, NaNWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "NaN", true);
+}
+
+TEST_F(LLVMLessThanTest, FalseBooleanWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, false, "Infinity");
+}
+
+TEST_F(LLVMLessThanTest, FalseBooleanWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, false, "Infinity");
+}
+
+TEST_F(LLVMLessThanTest, InfinityWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "Infinity", false);
+}
+
+TEST_F(LLVMLessThanTest, InfinityWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "Infinity", false);
+}
+
+TEST_F(LLVMLessThanTest, FalseBooleanWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, false, "-Infinity");
+}
+
+TEST_F(LLVMLessThanTest, FalseBooleanWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, false, "-Infinity");
+}
+
+TEST_F(LLVMLessThanTest, NegativeInfinityWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "-Infinity", false);
+}
+
+TEST_F(LLVMLessThanTest, NegativeInfinityWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "-Infinity", false);
+}
+
+TEST_F(LLVMLessThanTest, FalseBooleanWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, false, "NaN");
+}
+
+TEST_F(LLVMLessThanTest, FalseBooleanWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, false, "NaN");
+}
+
+TEST_F(LLVMLessThanTest, NaNWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "NaN", false);
+}
+
+TEST_F(LLVMLessThanTest, NaNWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "NaN", false);
+}
+
+TEST_F(LLVMLessThanTest, InfinityStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMLessThanTest, InfinityStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMLessThanTest, InfinityStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMLessThanTest, InfinityStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMLessThanTest, InfinityStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "Infinity", "NaN");
+}
+
+TEST_F(LLVMLessThanTest, InfinityStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "Infinity", "NaN");
+}
+
+TEST_F(LLVMLessThanTest, LowercaseInfinityStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "infinity", "Infinity");
+}
+
+TEST_F(LLVMLessThanTest, LowercaseInfinityStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "infinity", "Infinity");
+}
+
+TEST_F(LLVMLessThanTest, LowercaseInfinityStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "infinity", "-Infinity");
+}
+
+TEST_F(LLVMLessThanTest, LowercaseInfinityStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "infinity", "-Infinity");
+}
+
+TEST_F(LLVMLessThanTest, LowercaseInfinityStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "infinity", "NaN");
+}
+
+TEST_F(LLVMLessThanTest, LowercaseInfinityStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "infinity", "NaN");
+}
+
+TEST_F(LLVMLessThanTest, NegativeInfinityStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMLessThanTest, NegativeInfinityStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMLessThanTest, NegativeInfinityStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMLessThanTest, NegativeInfinityStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMLessThanTest, NegativeInfinityStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "-Infinity", "NaN");
+}
+
+TEST_F(LLVMLessThanTest, NegativeInfinityStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "-Infinity", "NaN");
+}
+
+TEST_F(LLVMLessThanTest, LowercaseNegativeInfinityStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "-infinity", "Infinity");
+}
+
+TEST_F(LLVMLessThanTest, LowercaseNegativeInfinityStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "-infinity", "Infinity");
+}
+
+TEST_F(LLVMLessThanTest, LowercaseNegativeInfinityStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "-infinity", "-Infinity");
+}
+
+TEST_F(LLVMLessThanTest, LowercaseNegativeInfinityStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "-infinity", "-Infinity");
+}
+
+TEST_F(LLVMLessThanTest, LowercaseNegativeInfinityStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "-infinity", "NaN");
+}
+
+TEST_F(LLVMLessThanTest, LowercaseNegativeInfinityStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "-infinity", "NaN");
+}
+
+TEST_F(LLVMLessThanTest, NaNStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "NaN", "Infinity");
+}
+
+TEST_F(LLVMLessThanTest, NaNStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "NaN", "Infinity");
+}
+
+TEST_F(LLVMLessThanTest, NaNStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "NaN", "-Infinity");
+}
+
+TEST_F(LLVMLessThanTest, NaNStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "NaN", "-Infinity");
+}
+
+TEST_F(LLVMLessThanTest, NaNStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "NaN", "NaN");
+}
+
+TEST_F(LLVMLessThanTest, NaNStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "NaN", "NaN");
+}
+
+TEST_F(LLVMLessThanTest, LowercaseNaNStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "nan", "Infinity");
+}
+
+TEST_F(LLVMLessThanTest, LowercaseNaNStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "nan", "Infinity");
+}
+
+TEST_F(LLVMLessThanTest, LowercaseNaNStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "nan", "-Infinity");
+}
+
+TEST_F(LLVMLessThanTest, LowercaseNaNStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "nan", "-Infinity");
+}
+
+TEST_F(LLVMLessThanTest, LowercaseNaNStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "nan", "NaN");
+}
+
+TEST_F(LLVMLessThanTest, LowercaseNaNStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "nan", "NaN");
+}
+
+TEST_F(LLVMLessThanTest, InfinityWithStringAbc)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "Infinity", "abc");
+}
+
+TEST_F(LLVMLessThanTest, InfinityWithStringAbc_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "Infinity", "abc");
+}
+
+TEST_F(LLVMLessThanTest, InfinityWithStringSpace)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "Infinity", " ");
+}
+
+TEST_F(LLVMLessThanTest, InfinityWithStringSpace_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "Infinity", " ");
+}
+
+TEST_F(LLVMLessThanTest, InfinityWithEmptyString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "Infinity", "");
+}
+
+TEST_F(LLVMLessThanTest, InfinityWithEmptyString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "Infinity", "");
+}
+
+TEST_F(LLVMLessThanTest, InfinityWithZeroString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "Infinity", "0");
+}
+
+TEST_F(LLVMLessThanTest, InfinityWithZeroString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "Infinity", "0");
+}
+
+TEST_F(LLVMLessThanTest, NegativeInfinityWithStringAbc)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "-Infinity", "abc");
+}
+
+TEST_F(LLVMLessThanTest, NegativeInfinityWithStringAbc_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "-Infinity", "abc");
+}
+
+TEST_F(LLVMLessThanTest, NegativeInfinityWithStringSpace)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "-Infinity", " ");
+}
+
+TEST_F(LLVMLessThanTest, NegativeInfinityWithStringSpace_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "-Infinity", " ");
+}
+
+TEST_F(LLVMLessThanTest, NegativeInfinityWithEmptyString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "-Infinity", "");
+}
+
+TEST_F(LLVMLessThanTest, NegativeInfinityWithEmptyString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "-Infinity", "");
+}
+
+TEST_F(LLVMLessThanTest, NegativeInfinityWithZeroString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "-Infinity", "0");
+}
+
+TEST_F(LLVMLessThanTest, NegativeInfinityWithZeroString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "-Infinity", "0");
+}
+
+TEST_F(LLVMLessThanTest, NaNWithStringAbc)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "NaN", "abc");
+}
+
+TEST_F(LLVMLessThanTest, NaNWithStringAbc_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "NaN", "abc");
+}
+
+TEST_F(LLVMLessThanTest, NaNWithStringSpace)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "NaN", " ");
+}
+
+TEST_F(LLVMLessThanTest, NaNWithStringSpace_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "NaN", " ");
+}
+
+TEST_F(LLVMLessThanTest, NaNWithEmptyString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "NaN", "");
+}
+
+TEST_F(LLVMLessThanTest, NaNWithEmptyString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "NaN", "");
+}
+
+TEST_F(LLVMLessThanTest, NaNWithZeroString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, false, "NaN", "0");
+}
+
+TEST_F(LLVMLessThanTest, NaNWithZeroString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::CmpLT, true, "NaN", "0");
+}
diff --git a/test/llvm/operators/logic/and_test.cpp b/test/llvm/operators/logic/and_test.cpp
new file mode 100644
index 00000000..8129b2e8
--- /dev/null
+++ b/test/llvm/operators/logic/and_test.cpp
@@ -0,0 +1,890 @@
+#include <gtest/gtest.h>
+#include <scratchcpp/value.h>
+
+#include "llvmtestutils.h"
+
+class LLVMAndTest : public testing::Test
+{
+    public:
+        LLVMTestUtils m_utils;
+};
+
+TEST_F(LLVMAndTest, NumberWithNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, 10, 8);
+}
+
+TEST_F(LLVMAndTest, NumberWithNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, 10, 8);
+}
+
+TEST_F(LLVMAndTest, SameNegativeDecimals)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, -4.25, -4.25);
+}
+
+TEST_F(LLVMAndTest, SameNegativeDecimals_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, -4.25, -4.25);
+}
+
+TEST_F(LLVMAndTest, DifferentDecimals)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, -4.25, 5.312);
+}
+
+TEST_F(LLVMAndTest, DifferentDecimals_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, -4.25, 5.312);
+}
+
+TEST_F(LLVMAndTest, TrueAndTrue)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, true, true);
+}
+
+TEST_F(LLVMAndTest, TrueAndTrue_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, true, true);
+}
+
+TEST_F(LLVMAndTest, TrueAndFalse)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, true, false);
+}
+
+TEST_F(LLVMAndTest, TrueAndFalse_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, true, false);
+}
+
+TEST_F(LLVMAndTest, FalseAndTrue)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, false, true);
+}
+
+TEST_F(LLVMAndTest, FalseAndTrue_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, false, true);
+}
+
+TEST_F(LLVMAndTest, NumberAndTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, 1, true);
+}
+
+TEST_F(LLVMAndTest, NumberAndTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, 1, true);
+}
+
+TEST_F(LLVMAndTest, NumberAndFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, 1, false);
+}
+
+TEST_F(LLVMAndTest, NumberAndFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, 1, false);
+}
+
+TEST_F(LLVMAndTest, StringAndString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "abc", "def");
+}
+
+TEST_F(LLVMAndTest, StringAndString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "abc", "def");
+}
+
+TEST_F(LLVMAndTest, TrueStringAndTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "true", "true");
+}
+
+TEST_F(LLVMAndTest, TrueStringAndTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "true", "true");
+}
+
+TEST_F(LLVMAndTest, TrueStringAndFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "true", "false");
+}
+
+TEST_F(LLVMAndTest, TrueStringAndFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "true", "false");
+}
+
+TEST_F(LLVMAndTest, FalseStringAndTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "false", "true");
+}
+
+TEST_F(LLVMAndTest, FalseStringAndTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "false", "true");
+}
+
+TEST_F(LLVMAndTest, FalseStringAndFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "false", "false");
+}
+
+TEST_F(LLVMAndTest, FalseStringAndFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "false", "false");
+}
+
+TEST_F(LLVMAndTest, NumberAndExactString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, 5.25, "5.25");
+}
+
+TEST_F(LLVMAndTest, NumberAndExactString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, 5.25, "5.25");
+}
+
+TEST_F(LLVMAndTest, ExactStringAndNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "5.25", 5.25);
+}
+
+TEST_F(LLVMAndTest, ExactStringAndNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "5.25", 5.25);
+}
+
+TEST_F(LLVMAndTest, ZeroAndOneString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, 0, "1");
+}
+
+TEST_F(LLVMAndTest, ZeroAndOneString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, 0, "1");
+}
+
+TEST_F(LLVMAndTest, OneStringAndZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "1", 0);
+}
+
+TEST_F(LLVMAndTest, OneStringAndZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "1", 0);
+}
+
+TEST_F(LLVMAndTest, ZeroAndTestString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, 0, "test");
+}
+
+TEST_F(LLVMAndTest, ZeroAndTestString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, 0, "test");
+}
+
+TEST_F(LLVMAndTest, TestStringAndZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "test", 0);
+}
+
+TEST_F(LLVMAndTest, TestStringAndZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "test", 0);
+}
+
+TEST_F(LLVMAndTest, InfinityAndInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMAndTest, InfinityAndInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMAndTest, NegativeInfinityAndNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMAndTest, NegativeInfinityAndNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMAndTest, NaNAndNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "NaN", "NaN");
+}
+
+TEST_F(LLVMAndTest, NaNAndNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "NaN", "NaN");
+}
+
+TEST_F(LLVMAndTest, InfinityAndNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMAndTest, InfinityAndNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMAndTest, NegativeInfinityAndInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMAndTest, NegativeInfinityAndInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMAndTest, InfinityAndNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "Infinity", "NaN");
+}
+
+TEST_F(LLVMAndTest, InfinityAndNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "Infinity", "NaN");
+}
+
+TEST_F(LLVMAndTest, NaNAndInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "NaN", "Infinity");
+}
+
+TEST_F(LLVMAndTest, NaNAndInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "NaN", "Infinity");
+}
+
+TEST_F(LLVMAndTest, NegativeInfinityAndNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "-Infinity", "NaN");
+}
+
+TEST_F(LLVMAndTest, NegativeInfinityAndNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "-Infinity", "NaN");
+}
+
+TEST_F(LLVMAndTest, NaNAndNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "NaN", "-Infinity");
+}
+
+TEST_F(LLVMAndTest, NaNAndNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "NaN", "-Infinity");
+}
+
+TEST_F(LLVMAndTest, TrueBooleanWithTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, true, "true");
+}
+
+TEST_F(LLVMAndTest, TrueBooleanWithTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, true, "true");
+}
+
+TEST_F(LLVMAndTest, TrueStringWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "true", true);
+}
+
+TEST_F(LLVMAndTest, TrueStringWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "true", true);
+}
+
+TEST_F(LLVMAndTest, FalseBooleanWithFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, false, "false");
+}
+
+TEST_F(LLVMAndTest, FalseBooleanWithFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, false, "false");
+}
+
+TEST_F(LLVMAndTest, FalseStringWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "false", false);
+}
+
+TEST_F(LLVMAndTest, FalseStringWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "false", false);
+}
+
+TEST_F(LLVMAndTest, FalseBooleanWithTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, false, "true");
+}
+
+TEST_F(LLVMAndTest, FalseBooleanWithTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, false, "true");
+}
+
+TEST_F(LLVMAndTest, TrueStringWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "true", false);
+}
+
+TEST_F(LLVMAndTest, TrueStringWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "true", false);
+}
+
+TEST_F(LLVMAndTest, TrueBooleanWithFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, true, "false");
+}
+
+TEST_F(LLVMAndTest, TrueBooleanWithFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, true, "false");
+}
+
+TEST_F(LLVMAndTest, FalseStringWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "false", true);
+}
+
+TEST_F(LLVMAndTest, FalseStringWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "false", true);
+}
+
+TEST_F(LLVMAndTest, TrueBooleanWithUppercaseTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, true, "TRUE");
+}
+
+TEST_F(LLVMAndTest, TrueBooleanWithUppercaseTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, true, "TRUE");
+}
+
+TEST_F(LLVMAndTest, UppercaseTrueStringWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "TRUE", true);
+}
+
+TEST_F(LLVMAndTest, UppercaseTrueStringWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "TRUE", true);
+}
+
+TEST_F(LLVMAndTest, FalseBooleanWithUppercaseFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, false, "FALSE");
+}
+
+TEST_F(LLVMAndTest, FalseBooleanWithUppercaseFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, false, "FALSE");
+}
+
+TEST_F(LLVMAndTest, UppercaseFalseStringWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "FALSE", false);
+}
+
+TEST_F(LLVMAndTest, UppercaseFalseStringWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "FALSE", false);
+}
+
+TEST_F(LLVMAndTest, TrueBooleanWithZeroPaddedOne)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, true, "00001");
+}
+
+TEST_F(LLVMAndTest, TrueBooleanWithZeroPaddedOne_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, true, "00001");
+}
+
+TEST_F(LLVMAndTest, ZeroPaddedOneWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "00001", true);
+}
+
+TEST_F(LLVMAndTest, ZeroPaddedOneWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "00001", true);
+}
+
+TEST_F(LLVMAndTest, TrueBooleanWithZeroPaddedZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, true, "00000");
+}
+
+TEST_F(LLVMAndTest, TrueBooleanWithZeroPaddedZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, true, "00000");
+}
+
+TEST_F(LLVMAndTest, ZeroPaddedZeroWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "00000", true);
+}
+
+TEST_F(LLVMAndTest, ZeroPaddedZeroWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "00000", true);
+}
+
+TEST_F(LLVMAndTest, FalseBooleanWithZeroPaddedZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, false, "00000");
+}
+
+TEST_F(LLVMAndTest, FalseBooleanWithZeroPaddedZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, false, "00000");
+}
+
+TEST_F(LLVMAndTest, ZeroPaddedZeroWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "00000", false);
+}
+
+TEST_F(LLVMAndTest, ZeroPaddedZeroWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "00000", false);
+}
+
+TEST_F(LLVMAndTest, TrueStringWithOne)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "true", 1);
+}
+
+TEST_F(LLVMAndTest, TrueStringWithOne_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "true", 1);
+}
+
+TEST_F(LLVMAndTest, OneWithTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, 1, "true");
+}
+
+TEST_F(LLVMAndTest, OneWithTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, 1, "true");
+}
+
+TEST_F(LLVMAndTest, TrueStringWithZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "true", 0);
+}
+
+TEST_F(LLVMAndTest, TrueStringWithZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "true", 0);
+}
+
+TEST_F(LLVMAndTest, ZeroWithTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, 0, "true");
+}
+
+TEST_F(LLVMAndTest, ZeroWithTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, 0, "true");
+}
+
+TEST_F(LLVMAndTest, FalseStringWithZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "false", 0);
+}
+
+TEST_F(LLVMAndTest, FalseStringWithZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "false", 0);
+}
+
+TEST_F(LLVMAndTest, ZeroWithFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, 0, "false");
+}
+
+TEST_F(LLVMAndTest, ZeroWithFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, 0, "false");
+}
+
+TEST_F(LLVMAndTest, FalseStringWithOne)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "false", 1);
+}
+
+TEST_F(LLVMAndTest, FalseStringWithOne_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "false", 1);
+}
+
+TEST_F(LLVMAndTest, OneWithFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, 1, "false");
+}
+
+TEST_F(LLVMAndTest, OneWithFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, 1, "false");
+}
+
+TEST_F(LLVMAndTest, TrueStringWithUppercaseTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "true", "TRUE");
+}
+
+TEST_F(LLVMAndTest, TrueStringWithUppercaseTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "true", "TRUE");
+}
+
+TEST_F(LLVMAndTest, TrueStringWithUppercaseFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "true", "FALSE");
+}
+
+TEST_F(LLVMAndTest, TrueStringWithUppercaseFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "true", "FALSE");
+}
+
+TEST_F(LLVMAndTest, FalseStringWithUppercaseFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "false", "FALSE");
+}
+
+TEST_F(LLVMAndTest, FalseStringWithUppercaseFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "false", "FALSE");
+}
+
+TEST_F(LLVMAndTest, FalseStringWithUppercaseTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "false", "TRUE");
+}
+
+TEST_F(LLVMAndTest, FalseStringWithUppercaseTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "false", "TRUE");
+}
+
+TEST_F(LLVMAndTest, TrueBooleanWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, true, "Infinity");
+}
+
+TEST_F(LLVMAndTest, TrueBooleanWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, true, "Infinity");
+}
+
+TEST_F(LLVMAndTest, InfinityWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "Infinity", true);
+}
+
+TEST_F(LLVMAndTest, InfinityWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "Infinity", true);
+}
+
+TEST_F(LLVMAndTest, TrueBooleanWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, true, "-Infinity");
+}
+
+TEST_F(LLVMAndTest, TrueBooleanWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, true, "-Infinity");
+}
+
+TEST_F(LLVMAndTest, NegativeInfinityWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "-Infinity", true);
+}
+
+TEST_F(LLVMAndTest, NegativeInfinityWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "-Infinity", true);
+}
+
+TEST_F(LLVMAndTest, TrueBooleanWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, true, "NaN");
+}
+
+TEST_F(LLVMAndTest, TrueBooleanWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, true, "NaN");
+}
+
+TEST_F(LLVMAndTest, NaNWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "NaN", true);
+}
+
+TEST_F(LLVMAndTest, NaNWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "NaN", true);
+}
+
+TEST_F(LLVMAndTest, FalseBooleanWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, false, "Infinity");
+}
+
+TEST_F(LLVMAndTest, FalseBooleanWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, false, "Infinity");
+}
+
+TEST_F(LLVMAndTest, InfinityWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "Infinity", false);
+}
+
+TEST_F(LLVMAndTest, InfinityWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "Infinity", false);
+}
+
+TEST_F(LLVMAndTest, FalseBooleanWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, false, "-Infinity");
+}
+
+TEST_F(LLVMAndTest, FalseBooleanWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, false, "-Infinity");
+}
+
+TEST_F(LLVMAndTest, NegativeInfinityWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "-Infinity", false);
+}
+
+TEST_F(LLVMAndTest, NegativeInfinityWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "-Infinity", false);
+}
+
+TEST_F(LLVMAndTest, FalseBooleanWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, false, "NaN");
+}
+
+TEST_F(LLVMAndTest, FalseBooleanWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, false, "NaN");
+}
+
+TEST_F(LLVMAndTest, NaNWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "NaN", false);
+}
+
+TEST_F(LLVMAndTest, NaNWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "NaN", false);
+}
+
+TEST_F(LLVMAndTest, InfinityStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMAndTest, InfinityStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMAndTest, InfinityStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMAndTest, InfinityStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMAndTest, InfinityStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "Infinity", "NaN");
+}
+
+TEST_F(LLVMAndTest, InfinityStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "Infinity", "NaN");
+}
+
+TEST_F(LLVMAndTest, LowercaseInfinityStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "infinity", "Infinity");
+}
+
+TEST_F(LLVMAndTest, LowercaseInfinityStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "infinity", "Infinity");
+}
+
+TEST_F(LLVMAndTest, LowercaseInfinityStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "infinity", "-Infinity");
+}
+
+TEST_F(LLVMAndTest, LowercaseInfinityStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "infinity", "-Infinity");
+}
+
+TEST_F(LLVMAndTest, LowercaseInfinityStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "infinity", "NaN");
+}
+
+TEST_F(LLVMAndTest, LowercaseInfinityStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "infinity", "NaN");
+}
+
+TEST_F(LLVMAndTest, NegativeInfinityStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMAndTest, NegativeInfinityStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMAndTest, NegativeInfinityStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMAndTest, NegativeInfinityStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMAndTest, NegativeInfinityStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "-Infinity", "NaN");
+}
+
+TEST_F(LLVMAndTest, NegativeInfinityStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "-Infinity", "NaN");
+}
+
+TEST_F(LLVMAndTest, LowercaseNegativeInfinityStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "-infinity", "Infinity");
+}
+
+TEST_F(LLVMAndTest, LowercaseNegativeInfinityStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "-infinity", "Infinity");
+}
+
+TEST_F(LLVMAndTest, LowercaseNegativeInfinityStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "-infinity", "-Infinity");
+}
+
+TEST_F(LLVMAndTest, LowercaseNegativeInfinityStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "-infinity", "-Infinity");
+}
+
+TEST_F(LLVMAndTest, LowercaseNegativeInfinityStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "-infinity", "NaN");
+}
+
+TEST_F(LLVMAndTest, LowercaseNegativeInfinityStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "-infinity", "NaN");
+}
+
+TEST_F(LLVMAndTest, NaNStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "NaN", "Infinity");
+}
+
+TEST_F(LLVMAndTest, NaNStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "NaN", "Infinity");
+}
+
+TEST_F(LLVMAndTest, NaNStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "NaN", "-Infinity");
+}
+
+TEST_F(LLVMAndTest, NaNStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "NaN", "-Infinity");
+}
+
+TEST_F(LLVMAndTest, NaNStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "NaN", "NaN");
+}
+
+TEST_F(LLVMAndTest, NaNStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "NaN", "NaN");
+}
+
+TEST_F(LLVMAndTest, LowercaseNaNStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "nan", "Infinity");
+}
+
+TEST_F(LLVMAndTest, LowercaseNaNStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "nan", "Infinity");
+}
+
+TEST_F(LLVMAndTest, LowercaseNaNStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "nan", "-Infinity");
+}
+
+TEST_F(LLVMAndTest, LowercaseNaNStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "nan", "-Infinity");
+}
+
+TEST_F(LLVMAndTest, LowercaseNaNStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, false, "nan", "NaN");
+}
+
+TEST_F(LLVMAndTest, LowercaseNaNStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::And, true, "nan", "NaN");
+}
diff --git a/test/llvm/operators/logic/not_test.cpp b/test/llvm/operators/logic/not_test.cpp
new file mode 100644
index 00000000..7c28e577
--- /dev/null
+++ b/test/llvm/operators/logic/not_test.cpp
@@ -0,0 +1,260 @@
+#include <gtest/gtest.h>
+#include <scratchcpp/value.h>
+
+#include "llvmtestutils.h"
+
+class LLVMNotTest : public testing::Test
+{
+    public:
+        LLVMTestUtils m_utils;
+};
+
+TEST_F(LLVMNotTest, PositiveNumber)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, 10);
+}
+
+TEST_F(LLVMNotTest, PositiveNumber_Const)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, 10);
+}
+
+TEST_F(LLVMNotTest, NegativeDecimal)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, -4.25);
+}
+
+TEST_F(LLVMNotTest, NegativeDecimal_Const)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, -4.25);
+}
+
+TEST_F(LLVMNotTest, PositiveDecimal)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, 5.312);
+}
+
+TEST_F(LLVMNotTest, PositiveDecimal_Const)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, 5.312);
+}
+
+TEST_F(LLVMNotTest, One)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, 1);
+}
+
+TEST_F(LLVMNotTest, One_Const)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, 1);
+}
+
+TEST_F(LLVMNotTest, Zero)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, 0);
+}
+
+TEST_F(LLVMNotTest, Zero_Const)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, 0);
+}
+
+TEST_F(LLVMNotTest, TrueBoolean)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, true);
+}
+
+TEST_F(LLVMNotTest, TrueBoolean_Const)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, true);
+}
+
+TEST_F(LLVMNotTest, FalseBoolean)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, false);
+}
+
+TEST_F(LLVMNotTest, FalseBoolean_Const)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, false);
+}
+
+TEST_F(LLVMNotTest, AbcString)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "abc");
+}
+
+TEST_F(LLVMNotTest, AbcString_Const)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "abc");
+}
+
+TEST_F(LLVMNotTest, NumericString)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "5.25");
+}
+
+TEST_F(LLVMNotTest, NumericString_Const)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "5.25");
+}
+
+TEST_F(LLVMNotTest, ZeroString)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "0");
+}
+
+TEST_F(LLVMNotTest, ZeroString_Const)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "0");
+}
+
+TEST_F(LLVMNotTest, Infinity)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "Infinity");
+}
+
+TEST_F(LLVMNotTest, Infinity_Const)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "Infinity");
+}
+
+TEST_F(LLVMNotTest, NegativeInfinity)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "-Infinity");
+}
+
+TEST_F(LLVMNotTest, NegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "-Infinity");
+}
+
+TEST_F(LLVMNotTest, NaN)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "NaN");
+}
+
+TEST_F(LLVMNotTest, NaN_Const)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "NaN");
+}
+
+TEST_F(LLVMNotTest, TrueString)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "true");
+}
+
+TEST_F(LLVMNotTest, TrueString_Const)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "true");
+}
+
+TEST_F(LLVMNotTest, FalseString)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "false");
+}
+
+TEST_F(LLVMNotTest, FalseString_Const)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "false");
+}
+
+TEST_F(LLVMNotTest, UppercaseTrueString)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "TRUE");
+}
+
+TEST_F(LLVMNotTest, UppercaseTrueString_Const)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "TRUE");
+}
+
+TEST_F(LLVMNotTest, UppercaseFalseString)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "FALSE");
+}
+
+TEST_F(LLVMNotTest, UppercaseFalseString_Const)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "FALSE");
+}
+
+TEST_F(LLVMNotTest, ZeroPaddedOne)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "00001");
+}
+
+TEST_F(LLVMNotTest, ZeroPaddedOne_Const)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "00001");
+}
+
+TEST_F(LLVMNotTest, ZeroPaddedZero)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "00000");
+}
+
+TEST_F(LLVMNotTest, ZeroPaddedZero_Const)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "00000");
+}
+
+TEST_F(LLVMNotTest, InfinityString)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "Infinity");
+}
+
+TEST_F(LLVMNotTest, InfinityString_Const)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "Infinity");
+}
+
+TEST_F(LLVMNotTest, LowercaseInfinityString)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "infinity");
+}
+
+TEST_F(LLVMNotTest, LowercaseInfinityString_Const)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "infinity");
+}
+
+TEST_F(LLVMNotTest, NegativeInfinityString)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "-Infinity");
+}
+
+TEST_F(LLVMNotTest, NegativeInfinityString_Const)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "-Infinity");
+}
+
+TEST_F(LLVMNotTest, LowercaseNegativeInfinityString)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "-infinity");
+}
+
+TEST_F(LLVMNotTest, LowercaseNegativeInfinityString_Const)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "-infinity");
+}
+
+TEST_F(LLVMNotTest, NaNString)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "NaN");
+}
+
+TEST_F(LLVMNotTest, NaNString_Const)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "NaN");
+}
+
+TEST_F(LLVMNotTest, LowercaseNaNString)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, false, "nan");
+}
+
+TEST_F(LLVMNotTest, LowercaseNaNString_Const)
+{
+    ASSERT_BOOL_OP1(m_utils, LLVMTestUtils::OpType::Not, true, "nan");
+}
diff --git a/test/llvm/operators/logic/or_test.cpp b/test/llvm/operators/logic/or_test.cpp
new file mode 100644
index 00000000..f16510c5
--- /dev/null
+++ b/test/llvm/operators/logic/or_test.cpp
@@ -0,0 +1,890 @@
+#include <gtest/gtest.h>
+#include <scratchcpp/value.h>
+
+#include "llvmtestutils.h"
+
+class LLVMOrTest : public testing::Test
+{
+    public:
+        LLVMTestUtils m_utils;
+};
+
+TEST_F(LLVMOrTest, NumberWithNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, 10, 8);
+}
+
+TEST_F(LLVMOrTest, NumberWithNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, 10, 8);
+}
+
+TEST_F(LLVMOrTest, SameNegativeDecimals)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, -4.25, -4.25);
+}
+
+TEST_F(LLVMOrTest, SameNegativeDecimals_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, -4.25, -4.25);
+}
+
+TEST_F(LLVMOrTest, DifferentDecimals)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, -4.25, 5.312);
+}
+
+TEST_F(LLVMOrTest, DifferentDecimals_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, -4.25, 5.312);
+}
+
+TEST_F(LLVMOrTest, TrueAndTrue)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, true, true);
+}
+
+TEST_F(LLVMOrTest, TrueAndTrue_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, true, true);
+}
+
+TEST_F(LLVMOrTest, TrueAndFalse)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, true, false);
+}
+
+TEST_F(LLVMOrTest, TrueAndFalse_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, true, false);
+}
+
+TEST_F(LLVMOrTest, FalseAndTrue)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, false, true);
+}
+
+TEST_F(LLVMOrTest, FalseAndTrue_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, false, true);
+}
+
+TEST_F(LLVMOrTest, NumberAndTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, 1, true);
+}
+
+TEST_F(LLVMOrTest, NumberAndTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, 1, true);
+}
+
+TEST_F(LLVMOrTest, NumberAndFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, 1, false);
+}
+
+TEST_F(LLVMOrTest, NumberAndFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, 1, false);
+}
+
+TEST_F(LLVMOrTest, StringAndString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "abc", "def");
+}
+
+TEST_F(LLVMOrTest, StringAndString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "abc", "def");
+}
+
+TEST_F(LLVMOrTest, TrueStringAndTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "true", "true");
+}
+
+TEST_F(LLVMOrTest, TrueStringAndTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "true", "true");
+}
+
+TEST_F(LLVMOrTest, TrueStringAndFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "true", "false");
+}
+
+TEST_F(LLVMOrTest, TrueStringAndFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "true", "false");
+}
+
+TEST_F(LLVMOrTest, FalseStringAndTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "false", "true");
+}
+
+TEST_F(LLVMOrTest, FalseStringAndTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "false", "true");
+}
+
+TEST_F(LLVMOrTest, FalseStringAndFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "false", "false");
+}
+
+TEST_F(LLVMOrTest, FalseStringAndFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "false", "false");
+}
+
+TEST_F(LLVMOrTest, NumberAndExactString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, 5.25, "5.25");
+}
+
+TEST_F(LLVMOrTest, NumberAndExactString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, 5.25, "5.25");
+}
+
+TEST_F(LLVMOrTest, ExactStringAndNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "5.25", 5.25);
+}
+
+TEST_F(LLVMOrTest, ExactStringAndNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "5.25", 5.25);
+}
+
+TEST_F(LLVMOrTest, ZeroAndOneString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, 0, "1");
+}
+
+TEST_F(LLVMOrTest, ZeroAndOneString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, 0, "1");
+}
+
+TEST_F(LLVMOrTest, OneStringAndZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "1", 0);
+}
+
+TEST_F(LLVMOrTest, OneStringAndZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "1", 0);
+}
+
+TEST_F(LLVMOrTest, ZeroAndTestString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, 0, "test");
+}
+
+TEST_F(LLVMOrTest, ZeroAndTestString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, 0, "test");
+}
+
+TEST_F(LLVMOrTest, TestStringAndZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "test", 0);
+}
+
+TEST_F(LLVMOrTest, TestStringAndZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "test", 0);
+}
+
+TEST_F(LLVMOrTest, InfinityAndInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMOrTest, InfinityAndInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMOrTest, NegativeInfinityAndNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMOrTest, NegativeInfinityAndNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMOrTest, NaNAndNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "NaN", "NaN");
+}
+
+TEST_F(LLVMOrTest, NaNAndNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "NaN", "NaN");
+}
+
+TEST_F(LLVMOrTest, InfinityAndNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMOrTest, InfinityAndNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMOrTest, NegativeInfinityAndInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMOrTest, NegativeInfinityAndInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMOrTest, InfinityAndNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "Infinity", "NaN");
+}
+
+TEST_F(LLVMOrTest, InfinityAndNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "Infinity", "NaN");
+}
+
+TEST_F(LLVMOrTest, NaNAndInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "NaN", "Infinity");
+}
+
+TEST_F(LLVMOrTest, NaNAndInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "NaN", "Infinity");
+}
+
+TEST_F(LLVMOrTest, NegativeInfinityAndNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "-Infinity", "NaN");
+}
+
+TEST_F(LLVMOrTest, NegativeInfinityAndNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "-Infinity", "NaN");
+}
+
+TEST_F(LLVMOrTest, NaNAndNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "NaN", "-Infinity");
+}
+
+TEST_F(LLVMOrTest, NaNAndNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "NaN", "-Infinity");
+}
+
+TEST_F(LLVMOrTest, TrueBooleanWithTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, true, "true");
+}
+
+TEST_F(LLVMOrTest, TrueBooleanWithTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, true, "true");
+}
+
+TEST_F(LLVMOrTest, TrueStringWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "true", true);
+}
+
+TEST_F(LLVMOrTest, TrueStringWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "true", true);
+}
+
+TEST_F(LLVMOrTest, FalseBooleanWithFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, false, "false");
+}
+
+TEST_F(LLVMOrTest, FalseBooleanWithFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, false, "false");
+}
+
+TEST_F(LLVMOrTest, FalseStringWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "false", false);
+}
+
+TEST_F(LLVMOrTest, FalseStringWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "false", false);
+}
+
+TEST_F(LLVMOrTest, FalseBooleanWithTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, false, "true");
+}
+
+TEST_F(LLVMOrTest, FalseBooleanWithTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, false, "true");
+}
+
+TEST_F(LLVMOrTest, TrueStringWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "true", false);
+}
+
+TEST_F(LLVMOrTest, TrueStringWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "true", false);
+}
+
+TEST_F(LLVMOrTest, TrueBooleanWithFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, true, "false");
+}
+
+TEST_F(LLVMOrTest, TrueBooleanWithFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, true, "false");
+}
+
+TEST_F(LLVMOrTest, FalseStringWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "false", true);
+}
+
+TEST_F(LLVMOrTest, FalseStringWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "false", true);
+}
+
+TEST_F(LLVMOrTest, TrueBooleanWithUppercaseTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, true, "TRUE");
+}
+
+TEST_F(LLVMOrTest, TrueBooleanWithUppercaseTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, true, "TRUE");
+}
+
+TEST_F(LLVMOrTest, UppercaseTrueStringWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "TRUE", true);
+}
+
+TEST_F(LLVMOrTest, UppercaseTrueStringWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "TRUE", true);
+}
+
+TEST_F(LLVMOrTest, FalseBooleanWithUppercaseFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, false, "FALSE");
+}
+
+TEST_F(LLVMOrTest, FalseBooleanWithUppercaseFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, false, "FALSE");
+}
+
+TEST_F(LLVMOrTest, UppercaseFalseStringWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "FALSE", false);
+}
+
+TEST_F(LLVMOrTest, UppercaseFalseStringWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "FALSE", false);
+}
+
+TEST_F(LLVMOrTest, TrueBooleanWithZeroPaddedOne)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, true, "00001");
+}
+
+TEST_F(LLVMOrTest, TrueBooleanWithZeroPaddedOne_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, true, "00001");
+}
+
+TEST_F(LLVMOrTest, ZeroPaddedOneWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "00001", true);
+}
+
+TEST_F(LLVMOrTest, ZeroPaddedOneWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "00001", true);
+}
+
+TEST_F(LLVMOrTest, TrueBooleanWithZeroPaddedZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, true, "00000");
+}
+
+TEST_F(LLVMOrTest, TrueBooleanWithZeroPaddedZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, true, "00000");
+}
+
+TEST_F(LLVMOrTest, ZeroPaddedZeroWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "00000", true);
+}
+
+TEST_F(LLVMOrTest, ZeroPaddedZeroWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "00000", true);
+}
+
+TEST_F(LLVMOrTest, FalseBooleanWithZeroPaddedZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, false, "00000");
+}
+
+TEST_F(LLVMOrTest, FalseBooleanWithZeroPaddedZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, false, "00000");
+}
+
+TEST_F(LLVMOrTest, ZeroPaddedZeroWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "00000", false);
+}
+
+TEST_F(LLVMOrTest, ZeroPaddedZeroWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "00000", false);
+}
+
+TEST_F(LLVMOrTest, TrueStringWithOne)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "true", 1);
+}
+
+TEST_F(LLVMOrTest, TrueStringWithOne_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "true", 1);
+}
+
+TEST_F(LLVMOrTest, OneWithTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, 1, "true");
+}
+
+TEST_F(LLVMOrTest, OneWithTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, 1, "true");
+}
+
+TEST_F(LLVMOrTest, TrueStringWithZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "true", 0);
+}
+
+TEST_F(LLVMOrTest, TrueStringWithZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "true", 0);
+}
+
+TEST_F(LLVMOrTest, ZeroWithTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, 0, "true");
+}
+
+TEST_F(LLVMOrTest, ZeroWithTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, 0, "true");
+}
+
+TEST_F(LLVMOrTest, FalseStringWithZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "false", 0);
+}
+
+TEST_F(LLVMOrTest, FalseStringWithZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "false", 0);
+}
+
+TEST_F(LLVMOrTest, ZeroWithFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, 0, "false");
+}
+
+TEST_F(LLVMOrTest, ZeroWithFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, 0, "false");
+}
+
+TEST_F(LLVMOrTest, FalseStringWithOne)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "false", 1);
+}
+
+TEST_F(LLVMOrTest, FalseStringWithOne_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "false", 1);
+}
+
+TEST_F(LLVMOrTest, OneWithFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, 1, "false");
+}
+
+TEST_F(LLVMOrTest, OneWithFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, 1, "false");
+}
+
+TEST_F(LLVMOrTest, TrueStringWithUppercaseTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "true", "TRUE");
+}
+
+TEST_F(LLVMOrTest, TrueStringWithUppercaseTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "true", "TRUE");
+}
+
+TEST_F(LLVMOrTest, TrueStringWithUppercaseFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "true", "FALSE");
+}
+
+TEST_F(LLVMOrTest, TrueStringWithUppercaseFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "true", "FALSE");
+}
+
+TEST_F(LLVMOrTest, FalseStringWithUppercaseFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "false", "FALSE");
+}
+
+TEST_F(LLVMOrTest, FalseStringWithUppercaseFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "false", "FALSE");
+}
+
+TEST_F(LLVMOrTest, FalseStringWithUppercaseTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "false", "TRUE");
+}
+
+TEST_F(LLVMOrTest, FalseStringWithUppercaseTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "false", "TRUE");
+}
+
+TEST_F(LLVMOrTest, TrueBooleanWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, true, "Infinity");
+}
+
+TEST_F(LLVMOrTest, TrueBooleanWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, true, "Infinity");
+}
+
+TEST_F(LLVMOrTest, InfinityWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "Infinity", true);
+}
+
+TEST_F(LLVMOrTest, InfinityWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "Infinity", true);
+}
+
+TEST_F(LLVMOrTest, TrueBooleanWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, true, "-Infinity");
+}
+
+TEST_F(LLVMOrTest, TrueBooleanWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, true, "-Infinity");
+}
+
+TEST_F(LLVMOrTest, NegativeInfinityWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "-Infinity", true);
+}
+
+TEST_F(LLVMOrTest, NegativeInfinityWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "-Infinity", true);
+}
+
+TEST_F(LLVMOrTest, TrueBooleanWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, true, "NaN");
+}
+
+TEST_F(LLVMOrTest, TrueBooleanWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, true, "NaN");
+}
+
+TEST_F(LLVMOrTest, NaNWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "NaN", true);
+}
+
+TEST_F(LLVMOrTest, NaNWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "NaN", true);
+}
+
+TEST_F(LLVMOrTest, FalseBooleanWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, false, "Infinity");
+}
+
+TEST_F(LLVMOrTest, FalseBooleanWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, false, "Infinity");
+}
+
+TEST_F(LLVMOrTest, InfinityWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "Infinity", false);
+}
+
+TEST_F(LLVMOrTest, InfinityWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "Infinity", false);
+}
+
+TEST_F(LLVMOrTest, FalseBooleanWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, false, "-Infinity");
+}
+
+TEST_F(LLVMOrTest, FalseBooleanWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, false, "-Infinity");
+}
+
+TEST_F(LLVMOrTest, NegativeInfinityWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "-Infinity", false);
+}
+
+TEST_F(LLVMOrTest, NegativeInfinityWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "-Infinity", false);
+}
+
+TEST_F(LLVMOrTest, FalseBooleanWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, false, "NaN");
+}
+
+TEST_F(LLVMOrTest, FalseBooleanWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, false, "NaN");
+}
+
+TEST_F(LLVMOrTest, NaNWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "NaN", false);
+}
+
+TEST_F(LLVMOrTest, NaNWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "NaN", false);
+}
+
+TEST_F(LLVMOrTest, InfinityStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMOrTest, InfinityStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMOrTest, InfinityStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMOrTest, InfinityStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMOrTest, InfinityStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "Infinity", "NaN");
+}
+
+TEST_F(LLVMOrTest, InfinityStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "Infinity", "NaN");
+}
+
+TEST_F(LLVMOrTest, LowercaseInfinityStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "infinity", "Infinity");
+}
+
+TEST_F(LLVMOrTest, LowercaseInfinityStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "infinity", "Infinity");
+}
+
+TEST_F(LLVMOrTest, LowercaseInfinityStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "infinity", "-Infinity");
+}
+
+TEST_F(LLVMOrTest, LowercaseInfinityStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "infinity", "-Infinity");
+}
+
+TEST_F(LLVMOrTest, LowercaseInfinityStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "infinity", "NaN");
+}
+
+TEST_F(LLVMOrTest, LowercaseInfinityStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "infinity", "NaN");
+}
+
+TEST_F(LLVMOrTest, NegativeInfinityStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMOrTest, NegativeInfinityStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMOrTest, NegativeInfinityStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMOrTest, NegativeInfinityStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMOrTest, NegativeInfinityStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "-Infinity", "NaN");
+}
+
+TEST_F(LLVMOrTest, NegativeInfinityStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "-Infinity", "NaN");
+}
+
+TEST_F(LLVMOrTest, LowercaseNegativeInfinityStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "-infinity", "Infinity");
+}
+
+TEST_F(LLVMOrTest, LowercaseNegativeInfinityStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "-infinity", "Infinity");
+}
+
+TEST_F(LLVMOrTest, LowercaseNegativeInfinityStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "-infinity", "-Infinity");
+}
+
+TEST_F(LLVMOrTest, LowercaseNegativeInfinityStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "-infinity", "-Infinity");
+}
+
+TEST_F(LLVMOrTest, LowercaseNegativeInfinityStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "-infinity", "NaN");
+}
+
+TEST_F(LLVMOrTest, LowercaseNegativeInfinityStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "-infinity", "NaN");
+}
+
+TEST_F(LLVMOrTest, NaNStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "NaN", "Infinity");
+}
+
+TEST_F(LLVMOrTest, NaNStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "NaN", "Infinity");
+}
+
+TEST_F(LLVMOrTest, NaNStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "NaN", "-Infinity");
+}
+
+TEST_F(LLVMOrTest, NaNStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "NaN", "-Infinity");
+}
+
+TEST_F(LLVMOrTest, NaNStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "NaN", "NaN");
+}
+
+TEST_F(LLVMOrTest, NaNStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "NaN", "NaN");
+}
+
+TEST_F(LLVMOrTest, LowercaseNaNStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "nan", "Infinity");
+}
+
+TEST_F(LLVMOrTest, LowercaseNaNStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "nan", "Infinity");
+}
+
+TEST_F(LLVMOrTest, LowercaseNaNStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "nan", "-Infinity");
+}
+
+TEST_F(LLVMOrTest, LowercaseNaNStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "nan", "-Infinity");
+}
+
+TEST_F(LLVMOrTest, LowercaseNaNStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, false, "nan", "NaN");
+}
+
+TEST_F(LLVMOrTest, LowercaseNaNStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::Or, true, "nan", "NaN");
+}
diff --git a/test/llvm/operators/math/abs_test.cpp b/test/llvm/operators/math/abs_test.cpp
new file mode 100644
index 00000000..1c49ace1
--- /dev/null
+++ b/test/llvm/operators/math/abs_test.cpp
@@ -0,0 +1,116 @@
+#include <gtest/gtest.h>
+#include <scratchcpp/value.h>
+
+#include "llvmtestutils.h"
+
+class LLVMAbsTest : public testing::Test
+{
+    public:
+        LLVMTestUtils m_utils;
+};
+
+TEST_F(LLVMAbsTest, PositiveFour)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, false, 4.0).toDouble(), 4.0);
+}
+
+TEST_F(LLVMAbsTest, PositiveFour_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, true, 4.0).toDouble(), 4.0);
+}
+
+TEST_F(LLVMAbsTest, PositiveDecimal)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, false, 3.2).toDouble(), 3.2);
+}
+
+TEST_F(LLVMAbsTest, PositiveDecimal_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, true, 3.2).toDouble(), 3.2);
+}
+
+TEST_F(LLVMAbsTest, NegativeTwo)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, false, -2.0).toDouble(), 2.0);
+}
+
+TEST_F(LLVMAbsTest, NegativeTwo_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, true, -2.0).toDouble(), 2.0);
+}
+
+TEST_F(LLVMAbsTest, NegativeDecimalTwoPointFive)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, false, -2.5).toDouble(), 2.5);
+}
+
+TEST_F(LLVMAbsTest, NegativeDecimalTwoPointFive_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, true, -2.5).toDouble(), 2.5);
+}
+
+TEST_F(LLVMAbsTest, NegativeDecimalTwoPointSix)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, false, -2.6).toDouble(), 2.6);
+}
+
+TEST_F(LLVMAbsTest, NegativeDecimalTwoPointSix_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, true, -2.6).toDouble(), 2.6);
+}
+
+TEST_F(LLVMAbsTest, PositiveZero)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, false, 0.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMAbsTest, PositiveZero_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, true, 0.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMAbsTest, NegativeZero)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, false, -0.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMAbsTest, NegativeZero_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, true, -0.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMAbsTest, PositiveInfinity)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, false, inf).toDouble(), inf);
+}
+
+TEST_F(LLVMAbsTest, PositiveInfinity_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, true, inf).toDouble(), inf);
+}
+
+TEST_F(LLVMAbsTest, NegativeInfinity)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, false, -inf).toDouble(), inf);
+}
+
+TEST_F(LLVMAbsTest, NegativeInfinity_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, true, -inf).toDouble(), inf);
+}
+
+TEST_F(LLVMAbsTest, NaN)
+{
+    static const double nan = std::numeric_limits<double>::quiet_NaN();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, false, nan).toDouble(), 0);
+}
+
+TEST_F(LLVMAbsTest, NaN_Const)
+{
+    static const double nan = std::numeric_limits<double>::quiet_NaN();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Abs, true, nan).toDouble(), 0);
+}
diff --git a/test/llvm/operators/math/acos_test.cpp b/test/llvm/operators/math/acos_test.cpp
new file mode 100644
index 00000000..dec02caf
--- /dev/null
+++ b/test/llvm/operators/math/acos_test.cpp
@@ -0,0 +1,126 @@
+#include <gtest/gtest.h>
+#include <scratchcpp/value.h>
+
+#include "llvmtestutils.h"
+
+class LLVMAcosTest : public testing::Test
+{
+    public:
+        LLVMTestUtils m_utils;
+};
+
+TEST_F(LLVMAcosTest, One)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, false, 1.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMAcosTest, One_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, true, 1.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMAcosTest, OneHalf)
+{
+    ASSERT_EQ(std::round(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, false, 0.5).toDouble() * 100) / 100, 60.0);
+}
+
+TEST_F(LLVMAcosTest, OneHalf_Const)
+{
+    ASSERT_EQ(std::round(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, true, 0.5).toDouble() * 100) / 100, 60.0);
+}
+
+TEST_F(LLVMAcosTest, PositiveZero)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, false, 0.0).toDouble(), 90.0);
+}
+
+TEST_F(LLVMAcosTest, PositiveZero_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, true, 0.0).toDouble(), 90.0);
+}
+
+TEST_F(LLVMAcosTest, NegativeZero)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, false, -0.0).toDouble(), 90.0);
+}
+
+TEST_F(LLVMAcosTest, NegativeZero_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, true, -0.0).toDouble(), 90.0);
+}
+
+TEST_F(LLVMAcosTest, NegativeOneHalf)
+{
+    ASSERT_EQ(std::round(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, false, -0.5).toDouble() * 100) / 100, 120.0);
+}
+
+TEST_F(LLVMAcosTest, NegativeOneHalf_Const)
+{
+    ASSERT_EQ(std::round(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, true, -0.5).toDouble() * 100) / 100, 120.0);
+}
+
+TEST_F(LLVMAcosTest, NegativeOne)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, false, -1.0).toDouble(), 180.0);
+}
+
+TEST_F(LLVMAcosTest, NegativeOne_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, true, -1.0).toDouble(), 180.0);
+}
+
+TEST_F(LLVMAcosTest, OutOfRangePositive)
+{
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, false, 1.1).isNaN());
+}
+
+TEST_F(LLVMAcosTest, OutOfRangePositive_Const)
+{
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, true, 1.1).isNaN());
+}
+
+TEST_F(LLVMAcosTest, OutOfRangeNegative)
+{
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, false, -1.2).isNaN());
+}
+
+TEST_F(LLVMAcosTest, OutOfRangeNegative_Const)
+{
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, true, -1.2).isNaN());
+}
+
+TEST_F(LLVMAcosTest, PositiveInfinity)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, false, inf).isNaN());
+}
+
+TEST_F(LLVMAcosTest, PositiveInfinity_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, true, inf).isNaN());
+}
+
+TEST_F(LLVMAcosTest, NegativeInfinity)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, false, -inf).isNaN());
+}
+
+TEST_F(LLVMAcosTest, NegativeInfinity_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, true, -inf).isNaN());
+}
+
+TEST_F(LLVMAcosTest, NaN)
+{
+    static const double nan = std::numeric_limits<double>::quiet_NaN();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, false, nan).toDouble(), 90.0);
+}
+
+TEST_F(LLVMAcosTest, NaN_Const)
+{
+    static const double nan = std::numeric_limits<double>::quiet_NaN();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Acos, true, nan).toDouble(), 90.0);
+}
diff --git a/test/llvm/operators/math/add_test.cpp b/test/llvm/operators/math/add_test.cpp
new file mode 100644
index 00000000..5fb706fe
--- /dev/null
+++ b/test/llvm/operators/math/add_test.cpp
@@ -0,0 +1,130 @@
+#include <gtest/gtest.h>
+#include <scratchcpp/value.h>
+
+#include "llvmtestutils.h"
+
+class LLVMAddTest : public testing::Test
+{
+    public:
+        LLVMTestUtils m_utils;
+};
+
+TEST_F(LLVMAddTest, PositiveIntegers)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, false, 50, 25);
+}
+
+TEST_F(LLVMAddTest, PositiveIntegers_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, true, 50, 25);
+}
+
+TEST_F(LLVMAddTest, NegativeWithPositive)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, false, -500, 25);
+}
+
+TEST_F(LLVMAddTest, NegativeWithPositive_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, true, -500, 25);
+}
+
+TEST_F(LLVMAddTest, NegativeIntegers)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, false, -500, -25);
+}
+
+TEST_F(LLVMAddTest, NegativeIntegers_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, true, -500, -25);
+}
+
+TEST_F(LLVMAddTest, StringDecimals)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, false, "2.54", "6.28");
+}
+
+TEST_F(LLVMAddTest, StringDecimals_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, true, "2.54", "6.28");
+}
+
+TEST_F(LLVMAddTest, MixedDecimalAndString)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, false, 2.54, "-6.28");
+}
+
+TEST_F(LLVMAddTest, MixedDecimalAndString_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, true, 2.54, "-6.28");
+}
+
+TEST_F(LLVMAddTest, BooleanValues)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, false, true, true);
+}
+
+TEST_F(LLVMAddTest, BooleanValues_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, true, true, true);
+}
+
+TEST_F(LLVMAddTest, InfinityPlusInfinity)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, false, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMAddTest, InfinityPlusInfinity_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, true, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMAddTest, InfinityPlusNegativeInfinity)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, false, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMAddTest, InfinityPlusNegativeInfinity_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, true, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMAddTest, NegativeInfinityPlusInfinity)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, false, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMAddTest, NegativeInfinityPlusInfinity_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, true, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMAddTest, NegativeInfinityPlusNegativeInfinity)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, false, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMAddTest, NegativeInfinityPlusNegativeInfinity_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, true, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMAddTest, NumberPlusNaN)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, false, 1, "NaN");
+}
+
+TEST_F(LLVMAddTest, NumberPlusNaN_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, true, 1, "NaN");
+}
+
+TEST_F(LLVMAddTest, NaNPlusNumber)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, false, "NaN", 1);
+}
+
+TEST_F(LLVMAddTest, NaNPlusNumber_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Add, true, "NaN", 1);
+}
diff --git a/test/llvm/operators/math/asin_test.cpp b/test/llvm/operators/math/asin_test.cpp
new file mode 100644
index 00000000..7ecf9daf
--- /dev/null
+++ b/test/llvm/operators/math/asin_test.cpp
@@ -0,0 +1,126 @@
+#include <gtest/gtest.h>
+#include <scratchcpp/value.h>
+
+#include "llvmtestutils.h"
+
+class LLVMAsinTest : public testing::Test
+{
+    public:
+        LLVMTestUtils m_utils;
+};
+
+TEST_F(LLVMAsinTest, One)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, false, 1.0).toDouble(), 90.0);
+}
+
+TEST_F(LLVMAsinTest, One_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, true, 1.0).toDouble(), 90.0);
+}
+
+TEST_F(LLVMAsinTest, OneHalf)
+{
+    ASSERT_EQ(std::round(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, false, 0.5).toDouble() * 100) / 100, 30.0);
+}
+
+TEST_F(LLVMAsinTest, OneHalf_Const)
+{
+    ASSERT_EQ(std::round(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, true, 0.5).toDouble() * 100) / 100, 30.0);
+}
+
+TEST_F(LLVMAsinTest, PositiveZero)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, false, 0.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMAsinTest, PositiveZero_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, true, 0.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMAsinTest, NegativeZero)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, false, -0.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMAsinTest, NegativeZero_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, true, -0.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMAsinTest, NegativeOneHalf)
+{
+    ASSERT_EQ(std::round(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, false, -0.5).toDouble() * 100) / 100, -30.0);
+}
+
+TEST_F(LLVMAsinTest, NegativeOneHalf_Const)
+{
+    ASSERT_EQ(std::round(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, true, -0.5).toDouble() * 100) / 100, -30.0);
+}
+
+TEST_F(LLVMAsinTest, NegativeOne)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, false, -1.0).toDouble(), -90.0);
+}
+
+TEST_F(LLVMAsinTest, NegativeOne_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, true, -1.0).toDouble(), -90.0);
+}
+
+TEST_F(LLVMAsinTest, OutOfRangePositive)
+{
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, false, 1.1).isNaN());
+}
+
+TEST_F(LLVMAsinTest, OutOfRangePositive_Const)
+{
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, true, 1.1).isNaN());
+}
+
+TEST_F(LLVMAsinTest, OutOfRangeNegative)
+{
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, false, -1.2).isNaN());
+}
+
+TEST_F(LLVMAsinTest, OutOfRangeNegative_Const)
+{
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, true, -1.2).isNaN());
+}
+
+TEST_F(LLVMAsinTest, PositiveInfinity)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, false, inf).isNaN());
+}
+
+TEST_F(LLVMAsinTest, PositiveInfinity_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, true, inf).isNaN());
+}
+
+TEST_F(LLVMAsinTest, NegativeInfinity)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, false, -inf).isNaN());
+}
+
+TEST_F(LLVMAsinTest, NegativeInfinity_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, true, -inf).isNaN());
+}
+
+TEST_F(LLVMAsinTest, NaN)
+{
+    static const double nan = std::numeric_limits<double>::quiet_NaN();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, false, nan).toDouble(), 0.0);
+}
+
+TEST_F(LLVMAsinTest, NaN_Const)
+{
+    static const double nan = std::numeric_limits<double>::quiet_NaN();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Asin, true, nan).toDouble(), 0.0);
+}
diff --git a/test/llvm/operators/math/atan_test.cpp b/test/llvm/operators/math/atan_test.cpp
new file mode 100644
index 00000000..e6b98377
--- /dev/null
+++ b/test/llvm/operators/math/atan_test.cpp
@@ -0,0 +1,86 @@
+#include <gtest/gtest.h>
+#include <scratchcpp/value.h>
+
+#include "llvmtestutils.h"
+
+class LLVMAtanTest : public testing::Test
+{
+    public:
+        LLVMTestUtils m_utils;
+};
+
+TEST_F(LLVMAtanTest, One)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Atan, false, 1.0).toDouble(), 45.0);
+}
+
+TEST_F(LLVMAtanTest, One_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Atan, true, 1.0).toDouble(), 45.0);
+}
+
+TEST_F(LLVMAtanTest, PositiveZero)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Atan, false, 0.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMAtanTest, PositiveZero_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Atan, true, 0.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMAtanTest, NegativeZero)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Atan, false, -0.0).toDouble(), -0.0);
+}
+
+TEST_F(LLVMAtanTest, NegativeZero_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Atan, true, -0.0).toDouble(), -0.0);
+}
+
+TEST_F(LLVMAtanTest, NegativeOne)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Atan, false, -1.0).toDouble(), -45.0);
+}
+
+TEST_F(LLVMAtanTest, NegativeOne_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Atan, true, -1.0).toDouble(), -45.0);
+}
+
+TEST_F(LLVMAtanTest, PositiveInfinity)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Atan, false, inf).toDouble(), 90.0);
+}
+
+TEST_F(LLVMAtanTest, PositiveInfinity_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Atan, true, inf).toDouble(), 90.0);
+}
+
+TEST_F(LLVMAtanTest, NegativeInfinity)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Atan, false, -inf).toDouble(), -90.0);
+}
+
+TEST_F(LLVMAtanTest, NegativeInfinity_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Atan, true, -inf).toDouble(), -90.0);
+}
+
+TEST_F(LLVMAtanTest, NaN)
+{
+    static const double nan = std::numeric_limits<double>::quiet_NaN();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Atan, false, nan).toDouble(), 0.0);
+}
+
+TEST_F(LLVMAtanTest, NaN_Const)
+{
+    static const double nan = std::numeric_limits<double>::quiet_NaN();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Atan, true, nan).toDouble(), 0.0);
+}
diff --git a/test/llvm/operators/math/ceil_test.cpp b/test/llvm/operators/math/ceil_test.cpp
new file mode 100644
index 00000000..4537c76f
--- /dev/null
+++ b/test/llvm/operators/math/ceil_test.cpp
@@ -0,0 +1,176 @@
+#include <gtest/gtest.h>
+#include <scratchcpp/value.h>
+
+#include "llvmtestutils.h"
+
+class LLVMCeilTest : public testing::Test
+{
+    public:
+        LLVMTestUtils m_utils;
+};
+
+TEST_F(LLVMCeilTest, EightPointZero)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, false, 8.0).toDouble(), 8.0);
+}
+
+TEST_F(LLVMCeilTest, EightPointZero_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, true, 8.0).toDouble(), 8.0);
+}
+
+TEST_F(LLVMCeilTest, ThreePointTwo)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, false, 3.2).toDouble(), 4.0);
+}
+
+TEST_F(LLVMCeilTest, ThreePointTwo_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, true, 3.2).toDouble(), 4.0);
+}
+
+TEST_F(LLVMCeilTest, ThreePointFive)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, false, 3.5).toDouble(), 4.0);
+}
+
+TEST_F(LLVMCeilTest, ThreePointFive_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, true, 3.5).toDouble(), 4.0);
+}
+
+TEST_F(LLVMCeilTest, ThreePointSix)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, false, 3.6).toDouble(), 4.0);
+}
+
+TEST_F(LLVMCeilTest, ThreePointSix_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, true, 3.6).toDouble(), 4.0);
+}
+
+TEST_F(LLVMCeilTest, ZeroPointFour)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, false, 0.4).toDouble(), 1.0);
+}
+
+TEST_F(LLVMCeilTest, ZeroPointFour_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, true, 0.4).toDouble(), 1.0);
+}
+
+TEST_F(LLVMCeilTest, PositiveZero)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, false, 0.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMCeilTest, PositiveZero_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, true, 0.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMCeilTest, NegativeZero)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, false, -0.0).toDouble(), -0.0);
+}
+
+TEST_F(LLVMCeilTest, NegativeZero_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, true, -0.0).toDouble(), -0.0);
+}
+
+TEST_F(LLVMCeilTest, NegativeTwoPointFour)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, false, -2.4).toDouble(), -2.0);
+}
+
+TEST_F(LLVMCeilTest, NegativeTwoPointFour_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, true, -2.4).toDouble(), -2.0);
+}
+
+TEST_F(LLVMCeilTest, NegativeTwoPointFive)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, false, -2.5).toDouble(), -2.0);
+}
+
+TEST_F(LLVMCeilTest, NegativeTwoPointFive_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, true, -2.5).toDouble(), -2.0);
+}
+
+TEST_F(LLVMCeilTest, NegativeTwoPointSix)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, false, -2.6).toDouble(), -2.0);
+}
+
+TEST_F(LLVMCeilTest, NegativeTwoPointSix_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, true, -2.6).toDouble(), -2.0);
+}
+
+TEST_F(LLVMCeilTest, NegativeZeroPointFour)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, false, -0.4).toDouble(), -0.0);
+}
+
+TEST_F(LLVMCeilTest, NegativeZeroPointFour_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, true, -0.4).toDouble(), -0.0);
+}
+
+TEST_F(LLVMCeilTest, NegativeZeroPointFive)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, false, -0.5).toDouble(), -0.0);
+}
+
+TEST_F(LLVMCeilTest, NegativeZeroPointFive_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, true, -0.5).toDouble(), -0.0);
+}
+
+TEST_F(LLVMCeilTest, NegativeZeroPointFiftyOne)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, false, -0.51).toDouble(), -0.0);
+}
+
+TEST_F(LLVMCeilTest, NegativeZeroPointFiftyOne_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, true, -0.51).toDouble(), -0.0);
+}
+
+TEST_F(LLVMCeilTest, PositiveInfinity)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, false, inf).toDouble(), inf);
+}
+
+TEST_F(LLVMCeilTest, PositiveInfinity_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, true, inf).toDouble(), inf);
+}
+
+TEST_F(LLVMCeilTest, NegativeInfinity)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, false, -inf).toDouble(), -inf);
+}
+
+TEST_F(LLVMCeilTest, NegativeInfinity_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, true, -inf).toDouble(), -inf);
+}
+
+TEST_F(LLVMCeilTest, NaN)
+{
+    static const double nan = std::numeric_limits<double>::quiet_NaN();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, false, nan).toDouble(), 0);
+}
+
+TEST_F(LLVMCeilTest, NaN_Const)
+{
+    static const double nan = std::numeric_limits<double>::quiet_NaN();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ceil, true, nan).toDouble(), 0);
+}
diff --git a/test/llvm/operators/math/cos_test.cpp b/test/llvm/operators/math/cos_test.cpp
new file mode 100644
index 00000000..0b5daf30
--- /dev/null
+++ b/test/llvm/operators/math/cos_test.cpp
@@ -0,0 +1,136 @@
+#include <gtest/gtest.h>
+#include <scratchcpp/value.h>
+
+#include "llvmtestutils.h"
+
+class LLVMCosTest : public testing::Test
+{
+    public:
+        LLVMTestUtils m_utils;
+};
+
+TEST_F(LLVMCosTest, SixtyDegrees)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, false, 60.0).toDouble(), 0.5);
+}
+
+TEST_F(LLVMCosTest, SixtyDegrees_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, true, 60.0).toDouble(), 0.5);
+}
+
+TEST_F(LLVMCosTest, NinetyDegrees)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, false, 90.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMCosTest, NinetyDegrees_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, true, 90.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMCosTest, SixHundredDegrees)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, false, 600.0).toDouble(), -0.5);
+}
+
+TEST_F(LLVMCosTest, SixHundredDegrees_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, true, 600.0).toDouble(), -0.5);
+}
+
+TEST_F(LLVMCosTest, AlmostNinetyDegrees)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, false, 89.9999999971352).toDouble(), 1e-10);
+}
+
+TEST_F(LLVMCosTest, AlmostNinetyDegrees_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, true, 89.9999999971352).toDouble(), 1e-10);
+}
+
+TEST_F(LLVMCosTest, VeryCloseToNinetyDegrees)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, false, 89.999999999).toDouble(), 0.0);
+}
+
+TEST_F(LLVMCosTest, VeryCloseToNinetyDegrees_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, true, 89.999999999).toDouble(), 0.0);
+}
+
+TEST_F(LLVMCosTest, NegativeSixtyDegrees)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, false, -60.0).toDouble(), 0.5);
+}
+
+TEST_F(LLVMCosTest, NegativeSixtyDegrees_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, true, -60.0).toDouble(), 0.5);
+}
+
+TEST_F(LLVMCosTest, NegativeNinetyDegrees)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, false, -90.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMCosTest, NegativeNinetyDegrees_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, true, -90.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMCosTest, PositiveZero)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, false, 0.0).toDouble(), 1.0);
+}
+
+TEST_F(LLVMCosTest, PositiveZero_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, true, 0.0).toDouble(), 1.0);
+}
+
+TEST_F(LLVMCosTest, NegativeZero)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, false, -0.0).toDouble(), 1.0);
+}
+
+TEST_F(LLVMCosTest, NegativeZero_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, true, -0.0).toDouble(), 1.0);
+}
+
+TEST_F(LLVMCosTest, PositiveInfinity)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, false, inf).isNaN());
+}
+
+TEST_F(LLVMCosTest, PositiveInfinity_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, true, inf).isNaN());
+}
+
+TEST_F(LLVMCosTest, NegativeInfinity)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, false, -inf).isNaN());
+}
+
+TEST_F(LLVMCosTest, NegativeInfinity_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, true, -inf).isNaN());
+}
+
+TEST_F(LLVMCosTest, NaN)
+{
+    static const double nan = std::numeric_limits<double>::quiet_NaN();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, false, nan).toDouble(), 1.0);
+}
+
+TEST_F(LLVMCosTest, NaN_Const)
+{
+    static const double nan = std::numeric_limits<double>::quiet_NaN();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Cos, true, nan).toDouble(), 1.0);
+}
diff --git a/test/llvm/operators/math/divide_test.cpp b/test/llvm/operators/math/divide_test.cpp
new file mode 100644
index 00000000..91e327d4
--- /dev/null
+++ b/test/llvm/operators/math/divide_test.cpp
@@ -0,0 +1,270 @@
+#include <gtest/gtest.h>
+#include <scratchcpp/value.h>
+
+#include "llvmtestutils.h"
+
+class LLVMDivideTest : public testing::Test
+{
+    public:
+        LLVMTestUtils m_utils;
+};
+
+TEST_F(LLVMDivideTest, PositiveIntegers)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, 50, 2);
+}
+
+TEST_F(LLVMDivideTest, PositiveIntegers_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, 50, 2);
+}
+
+TEST_F(LLVMDivideTest, NegativeWithPositive)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, -500, 25);
+}
+
+TEST_F(LLVMDivideTest, NegativeWithPositive_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, -500, 25);
+}
+
+TEST_F(LLVMDivideTest, StringNegativeWithNegative)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, "-500", -25);
+}
+
+TEST_F(LLVMDivideTest, StringNegativeWithNegative_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, "-500", -25);
+}
+
+TEST_F(LLVMDivideTest, StringDecimals)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, "3.5", "2.5");
+}
+
+TEST_F(LLVMDivideTest, StringDecimals_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, "3.5", "2.5");
+}
+
+TEST_F(LLVMDivideTest, BooleanValues)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, true, true);
+}
+
+TEST_F(LLVMDivideTest, BooleanValues_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, true, true);
+}
+
+TEST_F(LLVMDivideTest, InfinityDividedByInfinity)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMDivideTest, InfinityDividedByInfinity_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMDivideTest, InfinityDividedByZero)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, "Infinity", 0);
+}
+
+TEST_F(LLVMDivideTest, InfinityDividedByZero_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, "Infinity", 0);
+}
+
+TEST_F(LLVMDivideTest, InfinityDividedByPositive)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, "Infinity", 2);
+}
+
+TEST_F(LLVMDivideTest, InfinityDividedByPositive_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, "Infinity", 2);
+}
+
+TEST_F(LLVMDivideTest, InfinityDividedByNegative)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, "Infinity", -2);
+}
+
+TEST_F(LLVMDivideTest, InfinityDividedByNegative_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, "Infinity", -2);
+}
+
+TEST_F(LLVMDivideTest, InfinityDividedByNegativeInfinity)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMDivideTest, InfinityDividedByNegativeInfinity_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMDivideTest, NegativeInfinityDividedByInfinity)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMDivideTest, NegativeInfinityDividedByInfinity_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMDivideTest, NegativeInfinityDividedByZero)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, "-Infinity", 0);
+}
+
+TEST_F(LLVMDivideTest, NegativeInfinityDividedByZero_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, "-Infinity", 0);
+}
+
+TEST_F(LLVMDivideTest, NegativeInfinityDividedByPositive)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, "-Infinity", 2);
+}
+
+TEST_F(LLVMDivideTest, NegativeInfinityDividedByPositive_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, "-Infinity", 2);
+}
+
+TEST_F(LLVMDivideTest, NegativeInfinityDividedByNegative)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, "-Infinity", -2);
+}
+
+TEST_F(LLVMDivideTest, NegativeInfinityDividedByNegative_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, "-Infinity", -2);
+}
+
+TEST_F(LLVMDivideTest, NegativeInfinityDividedByNegativeInfinity)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMDivideTest, NegativeInfinityDividedByNegativeInfinity_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMDivideTest, ZeroDividedByInfinity)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, 0, "Infinity");
+}
+
+TEST_F(LLVMDivideTest, ZeroDividedByInfinity_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, 0, "Infinity");
+}
+
+TEST_F(LLVMDivideTest, PositiveDividedByInfinity)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, 2, "Infinity");
+}
+
+TEST_F(LLVMDivideTest, PositiveDividedByInfinity_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, 2, "Infinity");
+}
+
+TEST_F(LLVMDivideTest, NegativeDividedByInfinity)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, -2, "Infinity");
+}
+
+TEST_F(LLVMDivideTest, NegativeDividedByInfinity_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, -2, "Infinity");
+}
+
+TEST_F(LLVMDivideTest, ZeroDividedByNegativeInfinity)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, 0, "-Infinity");
+}
+
+TEST_F(LLVMDivideTest, ZeroDividedByNegativeInfinity_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, 0, "-Infinity");
+}
+
+TEST_F(LLVMDivideTest, PositiveDividedByNegativeInfinity)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, 2, "-Infinity");
+}
+
+TEST_F(LLVMDivideTest, PositiveDividedByNegativeInfinity_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, 2, "-Infinity");
+}
+
+TEST_F(LLVMDivideTest, NegativeDividedByNegativeInfinity)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, -2, "-Infinity");
+}
+
+TEST_F(LLVMDivideTest, NegativeDividedByNegativeInfinity_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, -2, "-Infinity");
+}
+
+TEST_F(LLVMDivideTest, NumberDividedByNaN)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, 1, "NaN");
+}
+
+TEST_F(LLVMDivideTest, NumberDividedByNaN_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, 1, "NaN");
+}
+
+TEST_F(LLVMDivideTest, NaNDividedByNumber)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, "NaN", 1);
+}
+
+TEST_F(LLVMDivideTest, NaNDividedByNumber_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, "NaN", 1);
+}
+
+TEST_F(LLVMDivideTest, PositiveDividedByZero)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, 5, 0);
+}
+
+TEST_F(LLVMDivideTest, PositiveDividedByZero_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, 5, 0);
+}
+
+TEST_F(LLVMDivideTest, NegativeDividedByZero)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, -5, 0);
+}
+
+TEST_F(LLVMDivideTest, NegativeDividedByZero_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, -5, 0);
+}
+
+TEST_F(LLVMDivideTest, ZeroDividedByZero)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, false, 0, 0);
+}
+
+TEST_F(LLVMDivideTest, ZeroDividedByZero_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Div, true, 0, 0);
+}
diff --git a/test/llvm/operators/math/exp10_test.cpp b/test/llvm/operators/math/exp10_test.cpp
new file mode 100644
index 00000000..b7ff6a25
--- /dev/null
+++ b/test/llvm/operators/math/exp10_test.cpp
@@ -0,0 +1,106 @@
+#include <gtest/gtest.h>
+#include <scratchcpp/value.h>
+
+#include "llvmtestutils.h"
+
+class LLVMExp10Test : public testing::Test
+{
+    public:
+        LLVMTestUtils m_utils;
+};
+
+TEST_F(LLVMExp10Test, One)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, false, 1.0).toDouble(), 10.0);
+}
+
+TEST_F(LLVMExp10Test, One_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, true, 1.0).toDouble(), 10.0);
+}
+
+TEST_F(LLVMExp10Test, Three)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, false, 3.0).toDouble(), 1000.0);
+}
+
+TEST_F(LLVMExp10Test, Three_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, true, 3.0).toDouble(), 1000.0);
+}
+
+TEST_F(LLVMExp10Test, PositiveZero)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, false, 0.0).toDouble(), 1.0);
+}
+
+TEST_F(LLVMExp10Test, PositiveZero_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, true, 0.0).toDouble(), 1.0);
+}
+
+TEST_F(LLVMExp10Test, NegativeZero)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, false, -0.0).toDouble(), 1.0);
+}
+
+TEST_F(LLVMExp10Test, NegativeZero_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, true, -0.0).toDouble(), 1.0);
+}
+
+TEST_F(LLVMExp10Test, NegativeOne)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, false, -1.0).toDouble(), 0.1);
+}
+
+TEST_F(LLVMExp10Test, NegativeOne_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, true, -1.0).toDouble(), 0.1);
+}
+
+TEST_F(LLVMExp10Test, NegativeFive)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, false, -5.0).toDouble(), 0.00001);
+}
+
+TEST_F(LLVMExp10Test, NegativeFive_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, true, -5.0).toDouble(), 0.00001);
+}
+
+TEST_F(LLVMExp10Test, PositiveInfinity)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, false, inf).toDouble(), inf);
+}
+
+TEST_F(LLVMExp10Test, PositiveInfinity_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, true, inf).toDouble(), inf);
+}
+
+TEST_F(LLVMExp10Test, NegativeInfinity)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, false, -inf).toDouble(), 0.0);
+}
+
+TEST_F(LLVMExp10Test, NegativeInfinity_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, true, -inf).toDouble(), 0.0);
+}
+
+TEST_F(LLVMExp10Test, NaN)
+{
+    static const double nan = std::numeric_limits<double>::quiet_NaN();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, false, nan).toDouble(), 1.0);
+}
+
+TEST_F(LLVMExp10Test, NaN_Const)
+{
+    static const double nan = std::numeric_limits<double>::quiet_NaN();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp10, true, nan).toDouble(), 1.0);
+}
diff --git a/test/llvm/operators/math/exp_test.cpp b/test/llvm/operators/math/exp_test.cpp
new file mode 100644
index 00000000..52fc6ecf
--- /dev/null
+++ b/test/llvm/operators/math/exp_test.cpp
@@ -0,0 +1,96 @@
+#include <gtest/gtest.h>
+#include <scratchcpp/value.h>
+
+#include "llvmtestutils.h"
+
+class LLVMExpTest : public testing::Test
+{
+    public:
+        LLVMTestUtils m_utils;
+};
+
+TEST_F(LLVMExpTest, One)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp, false, 1.0).toDouble(), std::exp(1.0));
+}
+
+TEST_F(LLVMExpTest, One_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp, true, 1.0).toDouble(), std::exp(1.0));
+}
+
+TEST_F(LLVMExpTest, ZeroPointFive)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp, false, 0.5).toDouble(), std::exp(0.5));
+}
+
+TEST_F(LLVMExpTest, ZeroPointFive_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp, true, 0.5).toDouble(), std::exp(0.5));
+}
+
+TEST_F(LLVMExpTest, PositiveZero)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp, false, 0.0).toDouble(), 1.0);
+}
+
+TEST_F(LLVMExpTest, PositiveZero_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp, true, 0.0).toDouble(), 1.0);
+}
+
+TEST_F(LLVMExpTest, NegativeZero)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp, false, -0.0).toDouble(), 1.0);
+}
+
+TEST_F(LLVMExpTest, NegativeZero_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp, true, -0.0).toDouble(), 1.0);
+}
+
+TEST_F(LLVMExpTest, NegativeZeroPointSeven)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp, false, -0.7).toDouble(), std::exp(-0.7));
+}
+
+TEST_F(LLVMExpTest, NegativeZeroPointSeven_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp, true, -0.7).toDouble(), std::exp(-0.7));
+}
+
+TEST_F(LLVMExpTest, PositiveInfinity)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp, false, inf).toDouble(), inf);
+}
+
+TEST_F(LLVMExpTest, PositiveInfinity_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp, true, inf).toDouble(), inf);
+}
+
+TEST_F(LLVMExpTest, NegativeInfinity)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp, false, -inf).toDouble(), 0.0);
+}
+
+TEST_F(LLVMExpTest, NegativeInfinity_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp, true, -inf).toDouble(), 0.0);
+}
+
+TEST_F(LLVMExpTest, NaN)
+{
+    static const double nan = std::numeric_limits<double>::quiet_NaN();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp, false, nan).toDouble(), 1.0);
+}
+
+TEST_F(LLVMExpTest, NaN_Const)
+{
+    static const double nan = std::numeric_limits<double>::quiet_NaN();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Exp, true, nan).toDouble(), 1.0);
+}
diff --git a/test/llvm/operators/math/floor_test.cpp b/test/llvm/operators/math/floor_test.cpp
new file mode 100644
index 00000000..8329bd02
--- /dev/null
+++ b/test/llvm/operators/math/floor_test.cpp
@@ -0,0 +1,166 @@
+#include <gtest/gtest.h>
+#include <scratchcpp/value.h>
+
+#include "llvmtestutils.h"
+
+class LLVMFloorTest : public testing::Test
+{
+    public:
+        LLVMTestUtils m_utils;
+};
+
+TEST_F(LLVMFloorTest, FourPointZero)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, false, 4.0).toDouble(), 4.0);
+}
+
+TEST_F(LLVMFloorTest, FourPointZero_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, true, 4.0).toDouble(), 4.0);
+}
+
+TEST_F(LLVMFloorTest, ThreePointTwo)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, false, 3.2).toDouble(), 3.0);
+}
+
+TEST_F(LLVMFloorTest, ThreePointTwo_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, true, 3.2).toDouble(), 3.0);
+}
+
+TEST_F(LLVMFloorTest, ThreePointFive)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, false, 3.5).toDouble(), 3.0);
+}
+
+TEST_F(LLVMFloorTest, ThreePointFive_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, true, 3.5).toDouble(), 3.0);
+}
+
+TEST_F(LLVMFloorTest, ThreePointSix)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, false, 3.6).toDouble(), 3.0);
+}
+
+TEST_F(LLVMFloorTest, ThreePointSix_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, true, 3.6).toDouble(), 3.0);
+}
+
+TEST_F(LLVMFloorTest, PositiveZero)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, false, 0.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMFloorTest, PositiveZero_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, true, 0.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMFloorTest, NegativeZero)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, false, -0.0).toDouble(), -0.0);
+}
+
+TEST_F(LLVMFloorTest, NegativeZero_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, true, -0.0).toDouble(), -0.0);
+}
+
+TEST_F(LLVMFloorTest, NegativeTwoPointFour)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, false, -2.4).toDouble(), -3.0);
+}
+
+TEST_F(LLVMFloorTest, NegativeTwoPointFour_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, true, -2.4).toDouble(), -3.0);
+}
+
+TEST_F(LLVMFloorTest, NegativeTwoPointFive)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, false, -2.5).toDouble(), -3.0);
+}
+
+TEST_F(LLVMFloorTest, NegativeTwoPointFive_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, true, -2.5).toDouble(), -3.0);
+}
+
+TEST_F(LLVMFloorTest, NegativeTwoPointSix)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, false, -2.6).toDouble(), -3.0);
+}
+
+TEST_F(LLVMFloorTest, NegativeTwoPointSix_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, true, -2.6).toDouble(), -3.0);
+}
+
+TEST_F(LLVMFloorTest, NegativeZeroPointFour)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, false, -0.4).toDouble(), -1.0);
+}
+
+TEST_F(LLVMFloorTest, NegativeZeroPointFour_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, true, -0.4).toDouble(), -1.0);
+}
+
+TEST_F(LLVMFloorTest, NegativeZeroPointFive)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, false, -0.5).toDouble(), -1.0);
+}
+
+TEST_F(LLVMFloorTest, NegativeZeroPointFive_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, true, -0.5).toDouble(), -1.0);
+}
+
+TEST_F(LLVMFloorTest, NegativeZeroPointFiftyOne)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, false, -0.51).toDouble(), -1.0);
+}
+
+TEST_F(LLVMFloorTest, NegativeZeroPointFiftyOne_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, true, -0.51).toDouble(), -1.0);
+}
+
+TEST_F(LLVMFloorTest, PositiveInfinity)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, false, inf).toDouble(), inf);
+}
+
+TEST_F(LLVMFloorTest, PositiveInfinity_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, true, inf).toDouble(), inf);
+}
+
+TEST_F(LLVMFloorTest, NegativeInfinity)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, false, -inf).toDouble(), -inf);
+}
+
+TEST_F(LLVMFloorTest, NegativeInfinity_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, true, -inf).toDouble(), -inf);
+}
+
+TEST_F(LLVMFloorTest, NaN)
+{
+    static const double nan = std::numeric_limits<double>::quiet_NaN();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, false, nan).toDouble(), 0);
+}
+
+TEST_F(LLVMFloorTest, NaN_Const)
+{
+    static const double nan = std::numeric_limits<double>::quiet_NaN();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Floor, true, nan).toDouble(), 0);
+}
diff --git a/test/llvm/operators/math/ln_test.cpp b/test/llvm/operators/math/ln_test.cpp
new file mode 100644
index 00000000..1a6763fa
--- /dev/null
+++ b/test/llvm/operators/math/ln_test.cpp
@@ -0,0 +1,122 @@
+#include <gtest/gtest.h>
+#include <scratchcpp/value.h>
+
+#include "llvmtestutils.h"
+
+class LLVMLnTest : public testing::Test
+{
+    public:
+        LLVMTestUtils m_utils;
+};
+
+TEST_F(LLVMLnTest, ExpOfOne)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, false, std::exp(1.0)).toDouble(), 1.0);
+}
+
+TEST_F(LLVMLnTest, ExpOfOne_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, true, std::exp(1.0)).toDouble(), 1.0);
+}
+
+TEST_F(LLVMLnTest, ExpOfTwo)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, false, std::exp(2.0)).toDouble(), 2.0);
+}
+
+TEST_F(LLVMLnTest, ExpOfTwo_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, true, std::exp(2.0)).toDouble(), 2.0);
+}
+
+TEST_F(LLVMLnTest, ExpOfZeroPointThree)
+{
+    ASSERT_EQ(std::round(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, false, std::exp(0.3)).toDouble() * 100) / 100, 0.3);
+}
+
+TEST_F(LLVMLnTest, ExpOfZeroPointThree_Const)
+{
+    ASSERT_EQ(std::round(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, true, std::exp(0.3)).toDouble() * 100) / 100, 0.3);
+}
+
+TEST_F(LLVMLnTest, One)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, false, 1.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMLnTest, One_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, true, 1.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMLnTest, PositiveZero)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, false, 0.0).toDouble(), -inf);
+}
+
+TEST_F(LLVMLnTest, PositiveZero_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, true, 0.0).toDouble(), -inf);
+}
+
+TEST_F(LLVMLnTest, NegativeZero)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, false, -0.0).toDouble(), -inf);
+}
+
+TEST_F(LLVMLnTest, NegativeZero_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, true, -0.0).toDouble(), -inf);
+}
+
+TEST_F(LLVMLnTest, NegativeNumber)
+{
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, false, -0.7).isNaN());
+}
+
+TEST_F(LLVMLnTest, NegativeNumber_Const)
+{
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, true, -0.7).isNaN());
+}
+
+TEST_F(LLVMLnTest, PositiveInfinity)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, false, inf).toDouble(), inf);
+}
+
+TEST_F(LLVMLnTest, PositiveInfinity_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, true, inf).toDouble(), inf);
+}
+
+TEST_F(LLVMLnTest, NegativeInfinity)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, false, -inf).isNaN());
+}
+
+TEST_F(LLVMLnTest, NegativeInfinity_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, true, -inf).isNaN());
+}
+
+TEST_F(LLVMLnTest, NaN)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    static const double nan = std::numeric_limits<double>::quiet_NaN();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, false, nan).toDouble(), -inf);
+}
+
+TEST_F(LLVMLnTest, NaN_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    static const double nan = std::numeric_limits<double>::quiet_NaN();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Ln, true, nan).toDouble(), -inf);
+}
diff --git a/test/llvm/operators/math/log10_test.cpp b/test/llvm/operators/math/log10_test.cpp
new file mode 100644
index 00000000..3b021f13
--- /dev/null
+++ b/test/llvm/operators/math/log10_test.cpp
@@ -0,0 +1,112 @@
+#include <gtest/gtest.h>
+#include <scratchcpp/value.h>
+
+#include "llvmtestutils.h"
+
+class LLVMLog10Test : public testing::Test
+{
+    public:
+        LLVMTestUtils m_utils;
+};
+
+TEST_F(LLVMLog10Test, Ten)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, false, 10.0).toDouble(), 1.0);
+}
+
+TEST_F(LLVMLog10Test, Ten_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, true, 10.0).toDouble(), 1.0);
+}
+
+TEST_F(LLVMLog10Test, OneThousand)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, false, 1000.0).toDouble(), 3.0);
+}
+
+TEST_F(LLVMLog10Test, OneThousand_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, true, 1000.0).toDouble(), 3.0);
+}
+
+TEST_F(LLVMLog10Test, ZeroPointZeroOne)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, false, 0.01).toDouble(), -2.0);
+}
+
+TEST_F(LLVMLog10Test, ZeroPointZeroOne_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, true, 0.01).toDouble(), -2.0);
+}
+
+TEST_F(LLVMLog10Test, PositiveZero)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, false, 0.0).toDouble(), -inf);
+}
+
+TEST_F(LLVMLog10Test, PositiveZero_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, true, 0.0).toDouble(), -inf);
+}
+
+TEST_F(LLVMLog10Test, NegativeZero)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, false, -0.0).toDouble(), -inf);
+}
+
+TEST_F(LLVMLog10Test, NegativeZero_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, true, -0.0).toDouble(), -inf);
+}
+
+TEST_F(LLVMLog10Test, NegativeNumber)
+{
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, false, -0.7).isNaN());
+}
+
+TEST_F(LLVMLog10Test, NegativeNumber_Const)
+{
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, true, -0.7).isNaN());
+}
+
+TEST_F(LLVMLog10Test, PositiveInfinity)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, false, inf).toDouble(), inf);
+}
+
+TEST_F(LLVMLog10Test, PositiveInfinity_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, true, inf).toDouble(), inf);
+}
+
+TEST_F(LLVMLog10Test, NegativeInfinity)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, false, -inf).isNaN());
+}
+
+TEST_F(LLVMLog10Test, NegativeInfinity_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, true, -inf).isNaN());
+}
+
+TEST_F(LLVMLog10Test, NaN)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    static const double nan = std::numeric_limits<double>::quiet_NaN();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, false, nan).toDouble(), -inf);
+}
+
+TEST_F(LLVMLog10Test, NaN_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    static const double nan = std::numeric_limits<double>::quiet_NaN();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Log10, true, nan).toDouble(), -inf);
+}
diff --git a/test/llvm/operators/math/mod_test.cpp b/test/llvm/operators/math/mod_test.cpp
new file mode 100644
index 00000000..93190c86
--- /dev/null
+++ b/test/llvm/operators/math/mod_test.cpp
@@ -0,0 +1,280 @@
+#include <gtest/gtest.h>
+#include <scratchcpp/value.h>
+
+#include "llvmtestutils.h"
+
+class LLVMModTest : public testing::Test
+{
+    public:
+        LLVMTestUtils m_utils;
+};
+
+TEST_F(LLVMModTest, FourModThree)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, 4, 3);
+}
+
+TEST_F(LLVMModTest, FourModThree_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, 4, 3);
+}
+
+TEST_F(LLVMModTest, ThreeModThree)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, 3, 3);
+}
+
+TEST_F(LLVMModTest, ThreeModThree_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, 3, 3);
+}
+
+TEST_F(LLVMModTest, TwoModThree)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, 2, 3);
+}
+
+TEST_F(LLVMModTest, TwoModThree_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, 2, 3);
+}
+
+TEST_F(LLVMModTest, OneModThree)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, 1, 3);
+}
+
+TEST_F(LLVMModTest, OneModThree_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, 1, 3);
+}
+
+TEST_F(LLVMModTest, ZeroModThree)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, 0, 3);
+}
+
+TEST_F(LLVMModTest, ZeroModThree_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, 0, 3);
+}
+
+TEST_F(LLVMModTest, NegativeOneModThree)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, -1, 3);
+}
+
+TEST_F(LLVMModTest, NegativeOneModThree_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, -1, 3);
+}
+
+TEST_F(LLVMModTest, NegativeTwoModThree)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, -2, 3);
+}
+
+TEST_F(LLVMModTest, NegativeTwoModThree_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, -2, 3);
+}
+
+TEST_F(LLVMModTest, NegativeThreeModThree)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, -3, 3);
+}
+
+TEST_F(LLVMModTest, NegativeThreeModThree_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, -3, 3);
+}
+
+TEST_F(LLVMModTest, NegativeFourModThree)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, -4, 3);
+}
+
+TEST_F(LLVMModTest, NegativeFourModThree_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, -4, 3);
+}
+
+TEST_F(LLVMModTest, DecimalModTwo)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, 4.75, 2);
+}
+
+TEST_F(LLVMModTest, DecimalModTwo_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, 4.75, 2);
+}
+
+TEST_F(LLVMModTest, NegativeDecimalModTwo)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, -4.75, 2);
+}
+
+TEST_F(LLVMModTest, NegativeDecimalModTwo_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, -4.75, 2);
+}
+
+TEST_F(LLVMModTest, NegativeDecimalModNegativeTwo)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, -4.75, -2);
+}
+
+TEST_F(LLVMModTest, NegativeDecimalModNegativeTwo_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, -4.75, -2);
+}
+
+TEST_F(LLVMModTest, DecimalModNegativeTwo)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, 4.75, -2);
+}
+
+TEST_F(LLVMModTest, DecimalModNegativeTwo_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, 4.75, -2);
+}
+
+TEST_F(LLVMModTest, FiveModZero)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, 5, 0);
+}
+
+TEST_F(LLVMModTest, FiveModZero_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, 5, 0);
+}
+
+TEST_F(LLVMModTest, NegativeFiveModZero)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, -5, 0);
+}
+
+TEST_F(LLVMModTest, NegativeFiveModZero_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, -5, 0);
+}
+
+TEST_F(LLVMModTest, NegativeDecimalModInfinity)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, -2.5, "Infinity");
+}
+
+TEST_F(LLVMModTest, NegativeDecimalModInfinity_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, -2.5, "Infinity");
+}
+
+TEST_F(LLVMModTest, NegativeDecimalModNegativeInfinity)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, -1.2, "-Infinity");
+}
+
+TEST_F(LLVMModTest, NegativeDecimalModNegativeInfinity_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, -1.2, "-Infinity");
+}
+
+TEST_F(LLVMModTest, PositiveDecimalModInfinity)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, 2.5, "Infinity");
+}
+
+TEST_F(LLVMModTest, PositiveDecimalModInfinity_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, 2.5, "Infinity");
+}
+
+TEST_F(LLVMModTest, PositiveDecimalModNegativeInfinity)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, 1.2, "-Infinity");
+}
+
+TEST_F(LLVMModTest, PositiveDecimalModNegativeInfinity_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, 1.2, "-Infinity");
+}
+
+TEST_F(LLVMModTest, InfinityModTwo)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, "Infinity", 2);
+}
+
+TEST_F(LLVMModTest, InfinityModTwo_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, "Infinity", 2);
+}
+
+TEST_F(LLVMModTest, NegativeInfinityModTwo)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, "-Infinity", 2);
+}
+
+TEST_F(LLVMModTest, NegativeInfinityModTwo_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, "-Infinity", 2);
+}
+
+TEST_F(LLVMModTest, InfinityModNegativeTwo)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, "Infinity", -2);
+}
+
+TEST_F(LLVMModTest, InfinityModNegativeTwo_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, "Infinity", -2);
+}
+
+TEST_F(LLVMModTest, NegativeInfinityModNegativeTwo)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, "-Infinity", -2);
+}
+
+TEST_F(LLVMModTest, NegativeInfinityModNegativeTwo_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, "-Infinity", -2);
+}
+
+TEST_F(LLVMModTest, ThreeModNaN)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, 3, "NaN");
+}
+
+TEST_F(LLVMModTest, ThreeModNaN_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, 3, "NaN");
+}
+
+TEST_F(LLVMModTest, NegativeThreeModNaN)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, -3, "NaN");
+}
+
+TEST_F(LLVMModTest, NegativeThreeModNaN_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, -3, "NaN");
+}
+
+TEST_F(LLVMModTest, NaNModFive)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, "NaN", 5);
+}
+
+TEST_F(LLVMModTest, NaNModFive_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, "NaN", 5);
+}
+
+TEST_F(LLVMModTest, NaNModNegativeFive)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, false, "NaN", -5);
+}
+
+TEST_F(LLVMModTest, NaNModNegativeFive_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mod, true, "NaN", -5);
+}
diff --git a/test/llvm/operators/math/multiply_test.cpp b/test/llvm/operators/math/multiply_test.cpp
new file mode 100644
index 00000000..acc36880
--- /dev/null
+++ b/test/llvm/operators/math/multiply_test.cpp
@@ -0,0 +1,180 @@
+#include <gtest/gtest.h>
+#include <scratchcpp/value.h>
+
+#include "llvmtestutils.h"
+
+class LLVMMultiplyTest : public testing::Test
+{
+    public:
+        LLVMTestUtils m_utils;
+};
+
+TEST_F(LLVMMultiplyTest, PositiveIntegers)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, false, 50, 2);
+}
+
+TEST_F(LLVMMultiplyTest, PositiveIntegers_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, true, 50, 2);
+}
+
+TEST_F(LLVMMultiplyTest, NegativeWithPositive)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, false, -500, 25);
+}
+
+TEST_F(LLVMMultiplyTest, NegativeWithPositive_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, true, -500, 25);
+}
+
+TEST_F(LLVMMultiplyTest, StringNegativeWithNegative)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, false, "-500", -25);
+}
+
+TEST_F(LLVMMultiplyTest, StringNegativeWithNegative_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, true, "-500", -25);
+}
+
+TEST_F(LLVMMultiplyTest, StringDecimals)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, false, "2.54", "6.28");
+}
+
+TEST_F(LLVMMultiplyTest, StringDecimals_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, true, "2.54", "6.28");
+}
+
+TEST_F(LLVMMultiplyTest, BooleanValues)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, false, true, true);
+}
+
+TEST_F(LLVMMultiplyTest, BooleanValues_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, true, true, true);
+}
+
+TEST_F(LLVMMultiplyTest, InfinityTimesInfinity)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, false, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMMultiplyTest, InfinityTimesInfinity_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, true, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMMultiplyTest, InfinityTimesZero)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, false, "Infinity", 0);
+}
+
+TEST_F(LLVMMultiplyTest, InfinityTimesZero_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, true, "Infinity", 0);
+}
+
+TEST_F(LLVMMultiplyTest, InfinityTimesPositive)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, false, "Infinity", 2);
+}
+
+TEST_F(LLVMMultiplyTest, InfinityTimesPositive_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, true, "Infinity", 2);
+}
+
+TEST_F(LLVMMultiplyTest, InfinityTimesNegative)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, false, "Infinity", -2);
+}
+
+TEST_F(LLVMMultiplyTest, InfinityTimesNegative_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, true, "Infinity", -2);
+}
+
+TEST_F(LLVMMultiplyTest, InfinityTimesNegativeInfinity)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, false, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMMultiplyTest, InfinityTimesNegativeInfinity_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, true, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMMultiplyTest, NegativeInfinityTimesInfinity)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, false, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMMultiplyTest, NegativeInfinityTimesInfinity_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, true, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMMultiplyTest, NegativeInfinityTimesZero)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, false, "-Infinity", 0);
+}
+
+TEST_F(LLVMMultiplyTest, NegativeInfinityTimesZero_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, true, "-Infinity", 0);
+}
+
+TEST_F(LLVMMultiplyTest, NegativeInfinityTimesPositive)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, false, "-Infinity", 2);
+}
+
+TEST_F(LLVMMultiplyTest, NegativeInfinityTimesPositive_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, true, "-Infinity", 2);
+}
+
+TEST_F(LLVMMultiplyTest, NegativeInfinityTimesNegative)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, false, "-Infinity", -2);
+}
+
+TEST_F(LLVMMultiplyTest, NegativeInfinityTimesNegative_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, true, "-Infinity", -2);
+}
+
+TEST_F(LLVMMultiplyTest, NegativeInfinityTimesNegativeInfinity)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, false, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMMultiplyTest, NegativeInfinityTimesNegativeInfinity_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, true, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMMultiplyTest, NumberTimesNaN)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, false, 1, "NaN");
+}
+
+TEST_F(LLVMMultiplyTest, NumberTimesNaN_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, true, 1, "NaN");
+}
+
+TEST_F(LLVMMultiplyTest, NaNTimesNumber)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, false, "NaN", 1);
+}
+
+TEST_F(LLVMMultiplyTest, NaNTimesNumber_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Mul, true, "NaN", 1);
+}
diff --git a/test/llvm/operators/math/random_int_test.cpp b/test/llvm/operators/math/random_int_test.cpp
new file mode 100644
index 00000000..d224a4da
--- /dev/null
+++ b/test/llvm/operators/math/random_int_test.cpp
@@ -0,0 +1,134 @@
+#include <gtest/gtest.h>
+#include <scratchcpp/value.h>
+
+#include "llvmtestutils.h"
+
+using ::testing::Return;
+
+class LLVMRandomIntTest : public testing::Test
+{
+    public:
+        LLVMTestUtils m_utils;
+};
+
+TEST_F(LLVMRandomIntTest, IntegerRange)
+{
+    EXPECT_CALL(m_utils.rng(), randint(-45, 12)).Times(2).WillRepeatedly(Return(-18));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, false, -45, 12);
+}
+
+TEST_F(LLVMRandomIntTest, IntegerRange_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randint(-45, 12)).Times(2).WillRepeatedly(Return(-18));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, true, -45, 12);
+}
+
+TEST_F(LLVMRandomIntTest, DoubleAsInteger)
+{
+    EXPECT_CALL(m_utils.rng(), randint(-45, 12)).Times(2).WillRepeatedly(Return(5));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, false, -45.0, 12.0);
+}
+
+TEST_F(LLVMRandomIntTest, DoubleAsInteger_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randint(-45, 12)).Times(2).WillRepeatedly(Return(5));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, true, -45.0, 12.0);
+}
+
+TEST_F(LLVMRandomIntTest, TruncatedDoubleRange)
+{
+    EXPECT_CALL(m_utils.rng(), randint(12, 6)).Times(2).WillRepeatedly(Return(3));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, false, 12, 6.05);
+}
+
+TEST_F(LLVMRandomIntTest, TruncatedDoubleRange_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randint(12, 6)).Times(2).WillRepeatedly(Return(3));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, true, 12, 6.05);
+}
+
+TEST_F(LLVMRandomIntTest, NegativeDoubleRange)
+{
+    EXPECT_CALL(m_utils.rng(), randint(-78, -45)).Times(2).WillRepeatedly(Return(-59));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, false, -78.686, -45);
+}
+
+TEST_F(LLVMRandomIntTest, NegativeDoubleRange_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randint(-78, -45)).Times(2).WillRepeatedly(Return(-59));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, true, -78.686, -45);
+}
+
+TEST_F(LLVMRandomIntTest, StringIntegerRange)
+{
+    EXPECT_CALL(m_utils.rng(), randint(-45, 12)).Times(2).WillRepeatedly(Return(0));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, false, "-45", "12");
+}
+
+TEST_F(LLVMRandomIntTest, StringIntegerRange_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randint(-45, 12)).Times(2).WillRepeatedly(Return(0));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, true, "-45", "12");
+}
+
+TEST_F(LLVMRandomIntTest, StringDoubleToInteger)
+{
+    EXPECT_CALL(m_utils.rng(), randint(-45, 12)).Times(2).WillRepeatedly(Return(5));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, false, "-45.0", "12");
+}
+
+TEST_F(LLVMRandomIntTest, StringDoubleToInteger_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randint(-45, 12)).Times(2).WillRepeatedly(Return(5));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, true, "-45.0", "12");
+}
+
+TEST_F(LLVMRandomIntTest, StringIntegerToDouble)
+{
+    EXPECT_CALL(m_utils.rng(), randint(-45, 12)).Times(2).WillRepeatedly(Return(-15));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, false, "-45", "12.0");
+}
+
+TEST_F(LLVMRandomIntTest, StringIntegerToDouble_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randint(-45, 12)).Times(2).WillRepeatedly(Return(-15));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, true, "-45", "12.0");
+}
+
+TEST_F(LLVMRandomIntTest, BooleanRange)
+{
+    EXPECT_CALL(m_utils.rng(), randint(0, 1)).Times(2).WillRepeatedly(Return(1));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, false, false, true);
+}
+
+TEST_F(LLVMRandomIntTest, BooleanRange_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randint(0, 1)).Times(2).WillRepeatedly(Return(1));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, true, false, true);
+}
+
+TEST_F(LLVMRandomIntTest, BooleanWithNumber)
+{
+    EXPECT_CALL(m_utils.rng(), randint(1, 5)).Times(2).WillRepeatedly(Return(1));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, false, true, 5);
+}
+
+TEST_F(LLVMRandomIntTest, BooleanWithNumber_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randint(1, 5)).Times(2).WillRepeatedly(Return(1));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, true, true, 5);
+}
+
+TEST_F(LLVMRandomIntTest, NumberWithBoolean)
+{
+    EXPECT_CALL(m_utils.rng(), randint(8, 0)).Times(2).WillRepeatedly(Return(1));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, false, 8, false);
+}
+
+TEST_F(LLVMRandomIntTest, NumberWithBoolean_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randint(8, 0)).Times(2).WillRepeatedly(Return(1));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::RandomInt, true, 8, false);
+}
+
+// NOTE: Infinity, -Infinity and NaN behavior is undefined
diff --git a/test/llvm/operators/math/random_test.cpp b/test/llvm/operators/math/random_test.cpp
new file mode 100644
index 00000000..fb66a65f
--- /dev/null
+++ b/test/llvm/operators/math/random_test.cpp
@@ -0,0 +1,444 @@
+#include <gtest/gtest.h>
+#include <scratchcpp/value.h>
+
+#include "llvmtestutils.h"
+
+using ::testing::Return;
+
+class LLVMRandomTest : public testing::Test
+{
+    public:
+        LLVMTestUtils m_utils;
+};
+
+TEST_F(LLVMRandomTest, IntegerRange)
+{
+    EXPECT_CALL(m_utils.rng(), randint(-45, 12)).WillRepeatedly(Return(-18));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, -45, 12);
+}
+
+TEST_F(LLVMRandomTest, IntegerRange_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randint(-45, 12)).WillRepeatedly(Return(-18));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, -45, 12);
+}
+
+TEST_F(LLVMRandomTest, DoubleAsInteger)
+{
+    EXPECT_CALL(m_utils.rng(), randint(-45, 12)).WillRepeatedly(Return(5));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, -45.0, 12.0);
+}
+
+TEST_F(LLVMRandomTest, DoubleAsInteger_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randint(-45, 12)).WillRepeatedly(Return(5));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, -45.0, 12.0);
+}
+
+TEST_F(LLVMRandomTest, DoubleRange)
+{
+    EXPECT_CALL(m_utils.rng(), randintDouble(12, 6.05)).WillRepeatedly(Return(3.486789));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, 12, 6.05);
+}
+
+TEST_F(LLVMRandomTest, DoubleRange_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randintDouble(12, 6.05)).WillRepeatedly(Return(3.486789));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, 12, 6.05);
+}
+
+TEST_F(LLVMRandomTest, NegativeDoubleRange)
+{
+    EXPECT_CALL(m_utils.rng(), randintDouble(-78.686, -45)).WillRepeatedly(Return(-59.468873));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, -78.686, -45);
+}
+
+TEST_F(LLVMRandomTest, NegativeDoubleRange_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randintDouble(-78.686, -45)).WillRepeatedly(Return(-59.468873));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, -78.686, -45);
+}
+
+TEST_F(LLVMRandomTest, ReversedDoubleRange)
+{
+    EXPECT_CALL(m_utils.rng(), randintDouble(6.05, -78.686)).WillRepeatedly(Return(-28.648764));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, 6.05, -78.686);
+}
+
+TEST_F(LLVMRandomTest, ReversedDoubleRange_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randintDouble(6.05, -78.686)).WillRepeatedly(Return(-28.648764));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, 6.05, -78.686);
+}
+
+TEST_F(LLVMRandomTest, StringIntegerRange)
+{
+    EXPECT_CALL(m_utils.rng(), randint(-45, 12)).WillRepeatedly(Return(0));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "-45", "12");
+}
+
+TEST_F(LLVMRandomTest, StringIntegerRange_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randint(-45, 12)).WillRepeatedly(Return(0));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "-45", "12");
+}
+
+TEST_F(LLVMRandomTest, StringDoubleToInteger)
+{
+    EXPECT_CALL(m_utils.rng(), randintDouble(-45, 12)).WillRepeatedly(Return(5.2));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "-45.0", "12");
+}
+
+TEST_F(LLVMRandomTest, StringDoubleToInteger_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randintDouble(-45, 12)).WillRepeatedly(Return(5.2));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "-45.0", "12");
+}
+
+TEST_F(LLVMRandomTest, StringIntegerToDouble)
+{
+    EXPECT_CALL(m_utils.rng(), randintDouble(-45, 12)).WillRepeatedly(Return(-15.5787));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "-45", "12.0");
+}
+
+TEST_F(LLVMRandomTest, StringIntegerToDouble_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randintDouble(-45, 12)).WillRepeatedly(Return(-15.5787));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "-45", "12.0");
+}
+
+TEST_F(LLVMRandomTest, StringDoubleRange)
+{
+    EXPECT_CALL(m_utils.rng(), randintDouble(-45, 12)).WillRepeatedly(Return(2.587964));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "-45.0", "12.0");
+}
+
+TEST_F(LLVMRandomTest, StringDoubleRange_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randintDouble(-45, 12)).WillRepeatedly(Return(2.587964));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "-45.0", "12.0");
+}
+
+TEST_F(LLVMRandomTest, StringReversedDoubleRange)
+{
+    EXPECT_CALL(m_utils.rng(), randintDouble(6.05, -78.686)).WillRepeatedly(Return(5.648764));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "6.05", "-78.686");
+}
+
+TEST_F(LLVMRandomTest, StringReversedDoubleRange_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randintDouble(6.05, -78.686)).WillRepeatedly(Return(5.648764));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "6.05", "-78.686");
+}
+
+TEST_F(LLVMRandomTest, MixedStringIntegerWithNumber)
+{
+    EXPECT_CALL(m_utils.rng(), randint(-45, 12)).WillRepeatedly(Return(0));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "-45", 12);
+}
+
+TEST_F(LLVMRandomTest, MixedStringIntegerWithNumber_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randint(-45, 12)).WillRepeatedly(Return(0));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "-45", 12);
+}
+
+TEST_F(LLVMRandomTest, MixedNumberWithStringInteger)
+{
+    EXPECT_CALL(m_utils.rng(), randint(-45, 12)).WillRepeatedly(Return(0));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, -45, "12");
+}
+
+TEST_F(LLVMRandomTest, MixedNumberWithStringInteger_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randint(-45, 12)).WillRepeatedly(Return(0));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, -45, "12");
+}
+
+TEST_F(LLVMRandomTest, MixedStringDoubleWithNumber)
+{
+    EXPECT_CALL(m_utils.rng(), randintDouble(-45, 12)).WillRepeatedly(Return(5.2));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "-45.0", 12);
+}
+
+TEST_F(LLVMRandomTest, MixedStringDoubleWithNumber_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randintDouble(-45, 12)).WillRepeatedly(Return(5.2));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "-45.0", 12);
+}
+
+TEST_F(LLVMRandomTest, MixedNumberWithStringDouble)
+{
+    EXPECT_CALL(m_utils.rng(), randintDouble(-45, 12)).WillRepeatedly(Return(-15.5787));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, -45, "12.0");
+}
+
+TEST_F(LLVMRandomTest, MixedNumberWithStringDouble_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randintDouble(-45, 12)).WillRepeatedly(Return(-15.5787));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, -45, "12.0");
+}
+
+TEST_F(LLVMRandomTest, MixedDoubleWithStringDouble)
+{
+    EXPECT_CALL(m_utils.rng(), randintDouble(6.05, -78.686)).WillRepeatedly(Return(5.648764));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, 6.05, "-78.686");
+}
+
+TEST_F(LLVMRandomTest, MixedDoubleWithStringDouble_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randintDouble(6.05, -78.686)).WillRepeatedly(Return(5.648764));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, 6.05, "-78.686");
+}
+
+TEST_F(LLVMRandomTest, MixedStringDoubleWithDouble)
+{
+    EXPECT_CALL(m_utils.rng(), randintDouble(6.05, -78.686)).WillRepeatedly(Return(5.648764));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "6.05", -78.686);
+}
+
+TEST_F(LLVMRandomTest, MixedStringDoubleWithDouble_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randintDouble(6.05, -78.686)).WillRepeatedly(Return(5.648764));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "6.05", -78.686);
+}
+
+TEST_F(LLVMRandomTest, BooleanRange)
+{
+    EXPECT_CALL(m_utils.rng(), randint(0, 1)).WillRepeatedly(Return(1));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, false, true);
+}
+
+TEST_F(LLVMRandomTest, BooleanRange_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randint(0, 1)).WillRepeatedly(Return(1));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, false, true);
+}
+
+TEST_F(LLVMRandomTest, BooleanWithNumber)
+{
+    EXPECT_CALL(m_utils.rng(), randint(1, 5)).WillRepeatedly(Return(1));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, true, 5);
+}
+
+TEST_F(LLVMRandomTest, BooleanWithNumber_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randint(1, 5)).WillRepeatedly(Return(1));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, true, 5);
+}
+
+TEST_F(LLVMRandomTest, NumberWithBoolean)
+{
+    EXPECT_CALL(m_utils.rng(), randint(8, 0)).WillRepeatedly(Return(1));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, 8, false);
+}
+
+TEST_F(LLVMRandomTest, NumberWithBoolean_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randint(8, 0)).WillRepeatedly(Return(1));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, 8, false);
+}
+
+TEST_F(LLVMRandomTest, NaNWithNumber)
+{
+    EXPECT_CALL(m_utils.rng(), randint(0, 5)).WillRepeatedly(Return(5));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "NaN", 5);
+}
+
+TEST_F(LLVMRandomTest, NaNWithNumber_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randint(0, 5)).WillRepeatedly(Return(5));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "NaN", 5);
+}
+
+TEST_F(LLVMRandomTest, NumberWithNaN)
+{
+    EXPECT_CALL(m_utils.rng(), randint(5, 0)).WillRepeatedly(Return(3));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, 5, "NaN");
+}
+
+TEST_F(LLVMRandomTest, NumberWithNaN_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randint(5, 0)).WillRepeatedly(Return(3));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, 5, "NaN");
+}
+
+TEST_F(LLVMRandomTest, NaNWithNaN)
+{
+    EXPECT_CALL(m_utils.rng(), randint(0, 0)).WillRepeatedly(Return(0));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "NaN", "NaN");
+}
+
+TEST_F(LLVMRandomTest, NaNWithNaN_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randint(0, 0)).WillRepeatedly(Return(0));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "NaN", "NaN");
+}
+
+TEST_F(LLVMRandomTest, InfinityWithNumber)
+{
+    EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0));
+    EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "Infinity", 2);
+}
+
+TEST_F(LLVMRandomTest, InfinityWithNumber_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0));
+    EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "Infinity", 2);
+}
+
+TEST_F(LLVMRandomTest, NumberWithInfinity)
+{
+    EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0));
+    EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, -8, "Infinity");
+}
+
+TEST_F(LLVMRandomTest, NumberWithInfinity_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0));
+    EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, -8, "Infinity");
+}
+
+TEST_F(LLVMRandomTest, NegativeInfinityWithNumber)
+{
+    EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0));
+    EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "-Infinity", -2);
+}
+
+TEST_F(LLVMRandomTest, NegativeInfinityWithNumber_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0));
+    EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "-Infinity", -2);
+}
+
+TEST_F(LLVMRandomTest, NumberWithNegativeInfinity)
+{
+    EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0));
+    EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, 8, "-Infinity");
+}
+
+TEST_F(LLVMRandomTest, NumberWithNegativeInfinity_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0));
+    EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, 8, "-Infinity");
+}
+
+TEST_F(LLVMRandomTest, InfinityWithDouble)
+{
+    EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0));
+    EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "Infinity", 2.5);
+}
+
+TEST_F(LLVMRandomTest, InfinityWithDouble_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0));
+    EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "Infinity", 2.5);
+}
+
+TEST_F(LLVMRandomTest, DoubleWithInfinity)
+{
+    EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0));
+    EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, -8.09, "Infinity");
+}
+
+TEST_F(LLVMRandomTest, DoubleWithInfinity_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0));
+    EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, -8.09, "Infinity");
+}
+
+TEST_F(LLVMRandomTest, NegativeInfinityWithDouble)
+{
+    EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0));
+    EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "-Infinity", -2.5);
+}
+
+TEST_F(LLVMRandomTest, NegativeInfinityWithDouble_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0));
+    EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "-Infinity", -2.5);
+}
+
+TEST_F(LLVMRandomTest, DoubleWithNegativeInfinity)
+{
+    EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0));
+    EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, 8.09, "-Infinity");
+}
+
+TEST_F(LLVMRandomTest, DoubleWithNegativeInfinity_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0));
+    EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, 8.09, "-Infinity");
+}
+
+TEST_F(LLVMRandomTest, InfinityWithInfinity)
+{
+    EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0));
+    EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMRandomTest, InfinityWithInfinity_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0));
+    EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMRandomTest, NegativeInfinityWithNegativeInfinity)
+{
+    EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0));
+    EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMRandomTest, NegativeInfinityWithNegativeInfinity_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0));
+    EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMRandomTest, InfinityWithNegativeInfinity)
+{
+    EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0));
+    EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMRandomTest, InfinityWithNegativeInfinity_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0));
+    EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMRandomTest, NegativeInfinityWithInfinity)
+{
+    EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0));
+    EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, false, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMRandomTest, NegativeInfinityWithInfinity_Const)
+{
+    EXPECT_CALL(m_utils.rng(), randint).WillRepeatedly(Return(0));
+    EXPECT_CALL(m_utils.rng(), randintDouble).WillRepeatedly(Return(0));
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Random, true, "-Infinity", "Infinity");
+}
diff --git a/test/llvm/operators/math/round_test.cpp b/test/llvm/operators/math/round_test.cpp
new file mode 100644
index 00000000..e5bb7b45
--- /dev/null
+++ b/test/llvm/operators/math/round_test.cpp
@@ -0,0 +1,146 @@
+#include <gtest/gtest.h>
+#include <scratchcpp/value.h>
+
+#include "llvmtestutils.h"
+
+class LLVMRoundTest : public testing::Test
+{
+    public:
+        LLVMTestUtils m_utils;
+};
+
+TEST_F(LLVMRoundTest, FourPointZero)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, false, 4.0).toDouble(), 4.0);
+}
+
+TEST_F(LLVMRoundTest, FourPointZero_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, true, 4.0).toDouble(), 4.0);
+}
+
+TEST_F(LLVMRoundTest, ThreePointTwo)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, false, 3.2).toDouble(), 3.0);
+}
+
+TEST_F(LLVMRoundTest, ThreePointTwo_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, true, 3.2).toDouble(), 3.0);
+}
+
+TEST_F(LLVMRoundTest, ThreePointFive)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, false, 3.5).toDouble(), 4.0);
+}
+
+TEST_F(LLVMRoundTest, ThreePointFive_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, true, 3.5).toDouble(), 4.0);
+}
+
+TEST_F(LLVMRoundTest, ThreePointSix)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, false, 3.6).toDouble(), 4.0);
+}
+
+TEST_F(LLVMRoundTest, ThreePointSix_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, true, 3.6).toDouble(), 4.0);
+}
+
+TEST_F(LLVMRoundTest, NegativeTwoPointFour)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, false, -2.4).toDouble(), -2.0);
+}
+
+TEST_F(LLVMRoundTest, NegativeTwoPointFour_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, true, -2.4).toDouble(), -2.0);
+}
+
+TEST_F(LLVMRoundTest, NegativeTwoPointFive)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, false, -2.5).toDouble(), -2.0);
+}
+
+TEST_F(LLVMRoundTest, NegativeTwoPointFive_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, true, -2.5).toDouble(), -2.0);
+}
+
+TEST_F(LLVMRoundTest, NegativeTwoPointSix)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, false, -2.6).toDouble(), -3.0);
+}
+
+TEST_F(LLVMRoundTest, NegativeTwoPointSix_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, true, -2.6).toDouble(), -3.0);
+}
+
+TEST_F(LLVMRoundTest, NegativeZeroPointFour)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, false, -0.4).toDouble(), -0.0);
+}
+
+TEST_F(LLVMRoundTest, NegativeZeroPointFour_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, true, -0.4).toDouble(), -0.0);
+}
+
+TEST_F(LLVMRoundTest, NegativeZeroPointFive)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, false, -0.5).toDouble(), -0.0);
+}
+
+TEST_F(LLVMRoundTest, NegativeZeroPointFive_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, true, -0.5).toDouble(), -0.0);
+}
+
+TEST_F(LLVMRoundTest, NegativeZeroPointFiftyOne)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, false, -0.51).toDouble(), -1.0);
+}
+
+TEST_F(LLVMRoundTest, NegativeZeroPointFiftyOne_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, true, -0.51).toDouble(), -1.0);
+}
+
+TEST_F(LLVMRoundTest, Infinity)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, false, inf).toDouble(), inf);
+}
+
+TEST_F(LLVMRoundTest, Infinity_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, true, inf).toDouble(), inf);
+}
+
+TEST_F(LLVMRoundTest, NegativeInfinity)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, false, -inf).toDouble(), -inf);
+}
+
+TEST_F(LLVMRoundTest, NegativeInfinity_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, true, -inf).toDouble(), -inf);
+}
+
+TEST_F(LLVMRoundTest, NaN)
+{
+    static const double nan = std::numeric_limits<double>::quiet_NaN();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, false, nan).toDouble(), 0);
+}
+
+TEST_F(LLVMRoundTest, NaN_Const)
+{
+    static const double nan = std::numeric_limits<double>::quiet_NaN();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Round, true, nan).toDouble(), 0);
+}
diff --git a/test/llvm/operators/math/sin_test.cpp b/test/llvm/operators/math/sin_test.cpp
new file mode 100644
index 00000000..caaa0ea0
--- /dev/null
+++ b/test/llvm/operators/math/sin_test.cpp
@@ -0,0 +1,136 @@
+#include <gtest/gtest.h>
+#include <scratchcpp/value.h>
+
+#include "llvmtestutils.h"
+
+class LLVMSinTest : public testing::Test
+{
+    public:
+        LLVMTestUtils m_utils;
+};
+
+TEST_F(LLVMSinTest, ThirtyDegrees)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, false, 30.0).toDouble(), 0.5);
+}
+
+TEST_F(LLVMSinTest, ThirtyDegrees_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, true, 30.0).toDouble(), 0.5);
+}
+
+TEST_F(LLVMSinTest, NinetyDegrees)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, false, 90.0).toDouble(), 1.0);
+}
+
+TEST_F(LLVMSinTest, NinetyDegrees_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, true, 90.0).toDouble(), 1.0);
+}
+
+TEST_F(LLVMSinTest, VerySmallAngle)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, false, 2.8e-9).toDouble(), 0.0);
+}
+
+TEST_F(LLVMSinTest, VerySmallAngle_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, true, 2.8e-9).toDouble(), 0.0);
+}
+
+TEST_F(LLVMSinTest, SlightlyLargerSmallAngle)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, false, 2.9e-9).toDouble(), 1e-10);
+}
+
+TEST_F(LLVMSinTest, SlightlyLargerSmallAngle_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, true, 2.9e-9).toDouble(), 1e-10);
+}
+
+TEST_F(LLVMSinTest, FiveSeventyDegrees)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, false, 570.0).toDouble(), -0.5);
+}
+
+TEST_F(LLVMSinTest, FiveSeventyDegrees_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, true, 570.0).toDouble(), -0.5);
+}
+
+TEST_F(LLVMSinTest, NegativeThirtyDegrees)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, false, -30.0).toDouble(), -0.5);
+}
+
+TEST_F(LLVMSinTest, NegativeThirtyDegrees_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, true, -30.0).toDouble(), -0.5);
+}
+
+TEST_F(LLVMSinTest, NegativeNinetyDegrees)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, false, -90.0).toDouble(), -1.0);
+}
+
+TEST_F(LLVMSinTest, NegativeNinetyDegrees_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, true, -90.0).toDouble(), -1.0);
+}
+
+TEST_F(LLVMSinTest, PositiveZero)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, false, 0.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMSinTest, PositiveZero_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, true, 0.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMSinTest, NegativeZero)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, false, -0.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMSinTest, NegativeZero_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, true, -0.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMSinTest, PositiveInfinity)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, false, inf).isNaN());
+}
+
+TEST_F(LLVMSinTest, PositiveInfinity_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, true, inf).isNaN());
+}
+
+TEST_F(LLVMSinTest, NegativeInfinity)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, false, -inf).isNaN());
+}
+
+TEST_F(LLVMSinTest, NegativeInfinity_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, true, -inf).isNaN());
+}
+
+TEST_F(LLVMSinTest, NaN)
+{
+    static const double nan = std::numeric_limits<double>::quiet_NaN();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, false, nan).toDouble(), 0);
+}
+
+TEST_F(LLVMSinTest, NaN_Const)
+{
+    static const double nan = std::numeric_limits<double>::quiet_NaN();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sin, true, nan).toDouble(), 0);
+}
diff --git a/test/llvm/operators/math/sqrt_test.cpp b/test/llvm/operators/math/sqrt_test.cpp
new file mode 100644
index 00000000..faab7f42
--- /dev/null
+++ b/test/llvm/operators/math/sqrt_test.cpp
@@ -0,0 +1,96 @@
+#include <gtest/gtest.h>
+#include <scratchcpp/value.h>
+
+#include "llvmtestutils.h"
+
+class LLVMSqrtTest : public testing::Test
+{
+    public:
+        LLVMTestUtils m_utils;
+};
+
+TEST_F(LLVMSqrtTest, SixteenPointZero)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sqrt, false, 16.0).toDouble(), 4.0);
+}
+
+TEST_F(LLVMSqrtTest, SixteenPointZero_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sqrt, true, 16.0).toDouble(), 4.0);
+}
+
+TEST_F(LLVMSqrtTest, ZeroPointZeroFour)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sqrt, false, 0.04).toDouble(), 0.2);
+}
+
+TEST_F(LLVMSqrtTest, ZeroPointZeroFour_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sqrt, true, 0.04).toDouble(), 0.2);
+}
+
+TEST_F(LLVMSqrtTest, PositiveZero)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sqrt, false, 0.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMSqrtTest, PositiveZero_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sqrt, true, 0.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMSqrtTest, NegativeZero)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sqrt, false, -0.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMSqrtTest, NegativeZero_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sqrt, true, -0.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMSqrtTest, NegativeFour)
+{
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Sqrt, false, -4.0).isNaN());
+}
+
+TEST_F(LLVMSqrtTest, NegativeFour_Const)
+{
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Sqrt, true, -4.0).isNaN());
+}
+
+TEST_F(LLVMSqrtTest, PositiveInfinity)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sqrt, false, inf).toDouble(), inf);
+}
+
+TEST_F(LLVMSqrtTest, PositiveInfinity_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sqrt, true, inf).toDouble(), inf);
+}
+
+TEST_F(LLVMSqrtTest, NegativeInfinity)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Sqrt, false, -inf).isNaN());
+}
+
+TEST_F(LLVMSqrtTest, NegativeInfinity_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Sqrt, true, -inf).isNaN());
+}
+
+TEST_F(LLVMSqrtTest, NaN)
+{
+    static const double nan = std::numeric_limits<double>::quiet_NaN();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sqrt, false, nan).toDouble(), 0);
+}
+
+TEST_F(LLVMSqrtTest, NaN_Const)
+{
+    static const double nan = std::numeric_limits<double>::quiet_NaN();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Sqrt, true, nan).toDouble(), 0);
+}
diff --git a/test/llvm/operators/math/subtract_test.cpp b/test/llvm/operators/math/subtract_test.cpp
new file mode 100644
index 00000000..aa24dd02
--- /dev/null
+++ b/test/llvm/operators/math/subtract_test.cpp
@@ -0,0 +1,130 @@
+#include <gtest/gtest.h>
+#include <scratchcpp/value.h>
+
+#include "llvmtestutils.h"
+
+class LLVMSubtractTest : public testing::Test
+{
+    public:
+        LLVMTestUtils m_utils;
+};
+
+TEST_F(LLVMSubtractTest, PositiveIntegers)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, false, 50, 25);
+}
+
+TEST_F(LLVMSubtractTest, PositiveIntegers_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, true, 50, 25);
+}
+
+TEST_F(LLVMSubtractTest, NegativeWithPositive)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, false, -500, 25);
+}
+
+TEST_F(LLVMSubtractTest, NegativeWithPositive_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, true, -500, 25);
+}
+
+TEST_F(LLVMSubtractTest, NegativeIntegers)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, false, -500, -25);
+}
+
+TEST_F(LLVMSubtractTest, NegativeIntegers_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, true, -500, -25);
+}
+
+TEST_F(LLVMSubtractTest, StringDecimals)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, false, "2.54", "6.28");
+}
+
+TEST_F(LLVMSubtractTest, StringDecimals_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, true, "2.54", "6.28");
+}
+
+TEST_F(LLVMSubtractTest, MixedDecimalAndString)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, false, 2.54, "-6.28");
+}
+
+TEST_F(LLVMSubtractTest, MixedDecimalAndString_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, true, 2.54, "-6.28");
+}
+
+TEST_F(LLVMSubtractTest, BooleanValues)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, false, true, true);
+}
+
+TEST_F(LLVMSubtractTest, BooleanValues_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, true, true, true);
+}
+
+TEST_F(LLVMSubtractTest, InfinityMinusInfinity)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, false, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMSubtractTest, InfinityMinusInfinity_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, true, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMSubtractTest, InfinityMinusNegativeInfinity)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, false, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMSubtractTest, InfinityMinusNegativeInfinity_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, true, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMSubtractTest, NegativeInfinityMinusInfinity)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, false, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMSubtractTest, NegativeInfinityMinusInfinity_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, true, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMSubtractTest, NegativeInfinityMinusNegativeInfinity)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, false, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMSubtractTest, NegativeInfinityMinusNegativeInfinity_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, true, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMSubtractTest, NumberMinusNaN)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, false, 1, "NaN");
+}
+
+TEST_F(LLVMSubtractTest, NumberMinusNaN_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, true, 1, "NaN");
+}
+
+TEST_F(LLVMSubtractTest, NaNMinusNumber)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, false, "NaN", 1);
+}
+
+TEST_F(LLVMSubtractTest, NaNMinusNumber_Const)
+{
+    ASSERT_NUM_OP2(m_utils, LLVMTestUtils::OpType::Sub, true, "NaN", 1);
+}
diff --git a/test/llvm/operators/math/tan_test.cpp b/test/llvm/operators/math/tan_test.cpp
new file mode 100644
index 00000000..c0f7f59f
--- /dev/null
+++ b/test/llvm/operators/math/tan_test.cpp
@@ -0,0 +1,188 @@
+#include <gtest/gtest.h>
+#include <scratchcpp/value.h>
+
+#include "llvmtestutils.h"
+
+class LLVMTanTest : public testing::Test
+{
+    public:
+        LLVMTestUtils m_utils;
+};
+
+TEST_F(LLVMTanTest, FortyFiveDegrees)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, false, 45.0).toDouble(), 1.0);
+}
+
+TEST_F(LLVMTanTest, FortyFiveDegrees_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, true, 45.0).toDouble(), 1.0);
+}
+
+TEST_F(LLVMTanTest, NinetyDegrees)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, false, 90.0).toDouble(), inf);
+}
+
+TEST_F(LLVMTanTest, NinetyDegrees_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, true, 90.0).toDouble(), inf);
+}
+
+TEST_F(LLVMTanTest, TwoSeventyDegrees)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, false, 270.0).toDouble(), -inf);
+}
+
+TEST_F(LLVMTanTest, TwoSeventyDegrees_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, true, 270.0).toDouble(), -inf);
+}
+
+TEST_F(LLVMTanTest, FourFiftyDegrees)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, false, 450.0).toDouble(), inf);
+}
+
+TEST_F(LLVMTanTest, FourFiftyDegrees_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, true, 450.0).toDouble(), inf);
+}
+
+TEST_F(LLVMTanTest, NegativeNinetyDegrees)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, false, -90.0).toDouble(), -inf);
+}
+
+TEST_F(LLVMTanTest, NegativeNinetyDegrees_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, true, -90.0).toDouble(), -inf);
+}
+
+TEST_F(LLVMTanTest, NegativeTwoSeventyDegrees)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, false, -270.0).toDouble(), inf);
+}
+
+TEST_F(LLVMTanTest, NegativeTwoSeventyDegrees_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, true, -270.0).toDouble(), inf);
+}
+
+TEST_F(LLVMTanTest, NegativeFourFiftyDegrees)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, false, -450.0).toDouble(), -inf);
+}
+
+TEST_F(LLVMTanTest, NegativeFourFiftyDegrees_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, true, -450.0).toDouble(), -inf);
+}
+
+TEST_F(LLVMTanTest, OneEightyDegrees)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, false, 180.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMTanTest, OneEightyDegrees_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, true, 180.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMTanTest, NegativeOneEightyDegrees)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, false, -180.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMTanTest, NegativeOneEightyDegrees_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, true, -180.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMTanTest, VerySmallAngle)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, false, 2.87e-9).toDouble(), 1e-10);
+}
+
+TEST_F(LLVMTanTest, VerySmallAngle_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, true, 2.87e-9).toDouble(), 1e-10);
+}
+
+TEST_F(LLVMTanTest, EvenSmallerAngle)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, false, 2.8647e-9).toDouble(), 0.0);
+}
+
+TEST_F(LLVMTanTest, EvenSmallerAngle_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, true, 2.8647e-9).toDouble(), 0.0);
+}
+
+TEST_F(LLVMTanTest, PositiveZero)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, false, 0.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMTanTest, PositiveZero_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, true, 0.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMTanTest, NegativeZero)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, false, -0.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMTanTest, NegativeZero_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, true, -0.0).toDouble(), 0.0);
+}
+
+TEST_F(LLVMTanTest, PositiveInfinity)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, false, inf).isNaN());
+}
+
+TEST_F(LLVMTanTest, PositiveInfinity_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, true, inf).isNaN());
+}
+
+TEST_F(LLVMTanTest, NegativeInfinity)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, false, -inf).isNaN());
+}
+
+TEST_F(LLVMTanTest, NegativeInfinity_Const)
+{
+    static const double inf = std::numeric_limits<double>::infinity();
+    ASSERT_TRUE(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, true, -inf).isNaN());
+}
+
+TEST_F(LLVMTanTest, NaN)
+{
+    static const double nan = std::numeric_limits<double>::quiet_NaN();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, false, nan).toDouble(), 0.0);
+}
+
+TEST_F(LLVMTanTest, NaN_Const)
+{
+    static const double nan = std::numeric_limits<double>::quiet_NaN();
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::Tan, true, nan).toDouble(), 0.0);
+}
diff --git a/test/llvm/operators/string/string_char_test.cpp b/test/llvm/operators/string/string_char_test.cpp
new file mode 100644
index 00000000..c8755a67
--- /dev/null
+++ b/test/llvm/operators/string/string_char_test.cpp
@@ -0,0 +1,80 @@
+#include <gtest/gtest.h>
+#include <scratchcpp/value.h>
+
+#include "llvmtestutils.h"
+
+class LLVMStringCharTest : public testing::Test
+{
+    public:
+        LLVMTestUtils m_utils;
+};
+
+TEST_F(LLVMStringCharTest, HelloWorldSecondChar)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringChar, false, "Hello world", 1).toString(), "e");
+}
+
+TEST_F(LLVMStringCharTest, HelloWorldSecondChar_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringChar, true, "Hello world", 1).toString(), "e");
+}
+
+TEST_F(LLVMStringCharTest, HelloWorldZeroIndex)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringChar, false, "Hello world", 0).toString(), "H");
+}
+
+TEST_F(LLVMStringCharTest, HelloWorldZeroIndex_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringChar, true, "Hello world", 0).toString(), "H");
+}
+
+TEST_F(LLVMStringCharTest, HelloWorldOutOfRange)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringChar, false, "Hello world", 11).toString(), "");
+}
+
+TEST_F(LLVMStringCharTest, HelloWorldOutOfRange_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringChar, true, "Hello world", 11).toString(), "");
+}
+
+TEST_F(LLVMStringCharTest, AbcThirdChar)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringChar, false, "abc", 2).toString(), "c");
+}
+
+TEST_F(LLVMStringCharTest, AbcThirdChar_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringChar, true, "abc", 2).toString(), "c");
+}
+
+TEST_F(LLVMStringCharTest, AbcNegativeIndex)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringChar, false, "abc", -1).toString(), "");
+}
+
+TEST_F(LLVMStringCharTest, AbcNegativeIndex_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringChar, true, "abc", -1).toString(), "");
+}
+
+TEST_F(LLVMStringCharTest, AbcOutOfRange)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringChar, false, "abc", 3).toString(), "");
+}
+
+TEST_F(LLVMStringCharTest, AbcOutOfRange_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringChar, true, "abc", 3).toString(), "");
+}
+
+TEST_F(LLVMStringCharTest, UnicodeString)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringChar, false, "ábč", 0).toString(), "á");
+}
+
+TEST_F(LLVMStringCharTest, UnicodeString_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringChar, true, "ábč", 0).toString(), "á");
+}
diff --git a/test/llvm/operators/string/string_concat_test.cpp b/test/llvm/operators/string/string_concat_test.cpp
new file mode 100644
index 00000000..9492b191
--- /dev/null
+++ b/test/llvm/operators/string/string_concat_test.cpp
@@ -0,0 +1,40 @@
+#include <gtest/gtest.h>
+#include <scratchcpp/value.h>
+
+#include "llvmtestutils.h"
+
+class LLVMStringConcatTest : public testing::Test
+{
+    public:
+        LLVMTestUtils m_utils;
+};
+
+TEST_F(LLVMStringConcatTest, HelloWorld)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringConcat, false, "Hello ", "world").toString(), "Hello world");
+}
+
+TEST_F(LLVMStringConcatTest, HelloWorld_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringConcat, true, "Hello ", "world").toString(), "Hello world");
+}
+
+TEST_F(LLVMStringConcatTest, AbcDef)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringConcat, false, "abc", "def").toString(), "abcdef");
+}
+
+TEST_F(LLVMStringConcatTest, AbcDef_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringConcat, true, "abc", "def").toString(), "abcdef");
+}
+
+TEST_F(LLVMStringConcatTest, UnicodeStrings)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringConcat, false, "ábč", "ďéfgh").toString(), "ábčďéfgh");
+}
+
+TEST_F(LLVMStringConcatTest, UnicodeStrings_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringConcat, true, "ábč", "ďéfgh").toString(), "ábčďéfgh");
+}
diff --git a/test/llvm/operators/string/string_equal_case_insensitive_test.cpp b/test/llvm/operators/string/string_equal_case_insensitive_test.cpp
new file mode 100644
index 00000000..3ef1b33a
--- /dev/null
+++ b/test/llvm/operators/string/string_equal_case_insensitive_test.cpp
@@ -0,0 +1,1210 @@
+#include <gtest/gtest.h>
+#include <scratchcpp/value.h>
+
+#include "llvmtestutils.h"
+
+class LLVMStringEqualCaseInsensitiveTest : public testing::Test
+{
+    public:
+        LLVMTestUtils m_utils;
+};
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, SameIntegers)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 10, 10);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, SameIntegers_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 10, 10);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentIntegers)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 10, 8);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentIntegers_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 10, 8);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentIntegersReversed)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 8, 10);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentIntegersReversed_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 8, 10);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, SameDecimals)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, -4.25, -4.25);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, SameDecimals_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, -4.25, -4.25);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentDecimals)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, -4.25, 5.312);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentDecimals_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, -4.25, 5.312);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentDecimalsReversed)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 5.312, -4.25);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentDecimalsReversed_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 5.312, -4.25);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, SameBooleans)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, true, true);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, SameBooleans_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, true, true);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentBooleans)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, true, false);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentBooleans_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, true, false);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentBooleansReversed)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, false, true);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentBooleansReversed_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, false, true);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 1, true);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 1, true);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 1, false);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 1, false);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, SameStrings)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "abC def", "abC def");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, SameStrings_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "abC def", "abC def");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, StringsCaseDifferent)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "abC def", "abc dEf");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, StringsCaseDifferent_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "abC def", "abc dEf");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentStrings)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "abC def", "ghi Jkl");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentStrings_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "abC def", "ghi Jkl");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentStringsLonger)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "abC def", "hello world");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentStringsLonger_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "abC def", "hello world");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, SpaceVsEmpty)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, " ", "");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, SpaceVsEmpty_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, " ", "");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, SpaceVsZeroString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, " ", "0");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, SpaceVsZeroString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, " ", "0");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, SpaceVsZeroNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, " ", 0);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, SpaceVsZeroNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, " ", 0);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroNumberVsSpace)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 0, " ");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroNumberVsSpace_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 0, " ");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, EmptyVsZeroString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "", "0");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, EmptyVsZeroString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "", "0");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, EmptyVsZeroNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "", 0);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, EmptyVsZeroNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "", 0);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroNumberVsEmpty)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 0, "");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroNumberVsEmpty_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 0, "");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroStringVsZeroNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "0", 0);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroStringVsZeroNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "0", 0);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroNumberVsZeroString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 0, "0");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroNumberVsZeroString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 0, "0");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberVsExactString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 5.25, "5.25");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberVsExactString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 5.25, "5.25");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, ExactStringVsNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "5.25", 5.25);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, ExactStringVsNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "5.25", 5.25);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberVsStringWithLeadingSpace)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 5.25, " 5.25");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberVsStringWithLeadingSpace_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 5.25, " 5.25");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, StringWithLeadingSpaceVsNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, " 5.25", 5.25);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, StringWithLeadingSpaceVsNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, " 5.25", 5.25);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberVsStringWithTrailingSpace)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 5.25, "5.25 ");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberVsStringWithTrailingSpace_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 5.25, "5.25 ");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, StringWithTrailingSpaceVsNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "5.25 ", 5.25);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, StringWithTrailingSpaceVsNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "5.25 ", 5.25);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberVsStringWithSurroundingSpaces)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 5.25, " 5.25 ");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberVsStringWithSurroundingSpaces_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 5.25, " 5.25 ");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, StringWithSurroundingSpacesVsNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, " 5.25 ", 5.25);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, StringWithSurroundingSpacesVsNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, " 5.25 ", 5.25);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberVsDifferentString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 5.25, "5.26");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberVsDifferentString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 5.25, "5.26");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentStringVsNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "5.26", 5.25);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentStringVsNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "5.26", 5.25);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentStringNumbers)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "5.25", "5.26");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, DifferentStringNumbers_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "5.25", "5.26");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberVsStringWithTrailingSpaces)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 5, "5  ");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberVsStringWithTrailingSpaces_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 5, "5  ");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, StringWithTrailingSpacesVsNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "5  ", 5);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, StringWithTrailingSpacesVsNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "5  ", 5);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroVsOneString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 0, "1");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroVsOneString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 0, "1");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, OneStringVsZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "1", 0);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, OneStringVsZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "1", 0);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroVsTestString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 0, "test");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroVsTestString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 0, "test");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, TestStringVsZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "test", 0);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, TestStringVsZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "test", 0);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "NaN", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "NaN", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "Infinity", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "Infinity", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "NaN", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "NaN", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "-Infinity", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "-Infinity", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "NaN", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "NaN", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 5, "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 5, "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 5, "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 5, "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 5, "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NumberWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 5, "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 0, "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 0, "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueBooleanWithTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, true, "true");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueBooleanWithTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, true, "true");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueStringWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "true", true);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueStringWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "true", true);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseBooleanWithFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, false, "false");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseBooleanWithFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, false, "false");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseStringWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "false", false);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseStringWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "false", false);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseBooleanWithTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, false, "true");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseBooleanWithTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, false, "true");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueStringWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "true", false);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueStringWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "true", false);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueBooleanWithFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, true, "false");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueBooleanWithFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, true, "false");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseStringWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "false", true);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseStringWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "false", true);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueBooleanWithUppercaseTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, true, "TRUE");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueBooleanWithUppercaseTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, true, "TRUE");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, UppercaseTrueStringWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "TRUE", true);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, UppercaseTrueStringWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "TRUE", true);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseBooleanWithUppercaseFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, false, "FALSE");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseBooleanWithUppercaseFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, false, "FALSE");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, UppercaseFalseStringWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "FALSE", false);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, UppercaseFalseStringWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "FALSE", false);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueBooleanWithZeroPaddedOne)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, true, "00001");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueBooleanWithZeroPaddedOne_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, true, "00001");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroPaddedOneWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "00001", true);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroPaddedOneWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "00001", true);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueBooleanWithZeroPaddedZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, true, "00000");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueBooleanWithZeroPaddedZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, true, "00000");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroPaddedZeroWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "00000", true);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroPaddedZeroWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "00000", true);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseBooleanWithZeroPaddedZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, false, "00000");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseBooleanWithZeroPaddedZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, false, "00000");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroPaddedZeroWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "00000", false);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroPaddedZeroWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "00000", false);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueStringWithOne)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "true", 1);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueStringWithOne_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "true", 1);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, OneWithTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 1, "true");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, OneWithTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 1, "true");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueStringWithZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "true", 0);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueStringWithZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "true", 0);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroWithTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 0, "true");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroWithTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 0, "true");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseStringWithZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "false", 0);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseStringWithZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "false", 0);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroWithFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 0, "false");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, ZeroWithFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 0, "false");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseStringWithOne)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "false", 1);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseStringWithOne_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "false", 1);
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, OneWithFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, 1, "false");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, OneWithFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, 1, "false");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueStringWithUppercaseTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "true", "TRUE");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueStringWithUppercaseTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "true", "TRUE");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueStringWithUppercaseFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "true", "FALSE");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueStringWithUppercaseFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "true", "FALSE");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseStringWithUppercaseFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "false", "FALSE");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseStringWithUppercaseFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "false", "FALSE");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseStringWithUppercaseTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "false", "TRUE");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseStringWithUppercaseTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "false", "TRUE");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueBooleanWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, true, "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueBooleanWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, true, "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueBooleanWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, true, "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueBooleanWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, true, "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueBooleanWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, true, "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, TrueBooleanWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, true, "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseBooleanWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, false, "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseBooleanWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, false, "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseBooleanWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, false, "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseBooleanWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, false, "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseBooleanWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, false, "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, FalseBooleanWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, false, "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "Infinity", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "Infinity", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseInfinityStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "infinity", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseInfinityStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "infinity", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseInfinityStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "infinity", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseInfinityStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "infinity", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseInfinityStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "infinity", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseInfinityStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "infinity", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "-Infinity", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "-Infinity", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseNegativeInfinityStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "-infinity", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseNegativeInfinityStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "-infinity", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseNegativeInfinityStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "-infinity", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseNegativeInfinityStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "-infinity", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseNegativeInfinityStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "-infinity", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseNegativeInfinityStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "-infinity", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "NaN", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "NaN", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "NaN", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "NaN", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "NaN", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "NaN", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseNaNStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "nan", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseNaNStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "nan", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseNaNStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "nan", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseNaNStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "nan", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseNaNStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "nan", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, LowercaseNaNStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "nan", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityWithStringAbc)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "Infinity", "abc");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityWithStringAbc_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "Infinity", "abc");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityWithStringSpace)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "Infinity", " ");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityWithStringSpace_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "Infinity", " ");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityWithEmptyString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "Infinity", "");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityWithEmptyString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "Infinity", "");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityWithZeroString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "Infinity", "0");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, InfinityWithZeroString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "Infinity", "0");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityWithStringAbc)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "-Infinity", "abc");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityWithStringAbc_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "-Infinity", "abc");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityWithStringSpace)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "-Infinity", " ");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityWithStringSpace_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "-Infinity", " ");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityWithEmptyString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "-Infinity", "");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityWithEmptyString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "-Infinity", "");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityWithZeroString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "-Infinity", "0");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NegativeInfinityWithZeroString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "-Infinity", "0");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNWithStringAbc)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "NaN", "abc");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNWithStringAbc_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "NaN", "abc");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNWithStringSpace)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "NaN", " ");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNWithStringSpace_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "NaN", " ");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNWithEmptyString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "NaN", "");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNWithEmptyString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "NaN", "");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNWithZeroString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, false, "NaN", "0");
+}
+
+TEST_F(LLVMStringEqualCaseInsensitiveTest, NaNWithZeroString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCI, true, "NaN", "0");
+}
diff --git a/test/llvm/operators/string/string_equal_case_sensitive_test.cpp b/test/llvm/operators/string/string_equal_case_sensitive_test.cpp
new file mode 100644
index 00000000..fc8ae7db
--- /dev/null
+++ b/test/llvm/operators/string/string_equal_case_sensitive_test.cpp
@@ -0,0 +1,1210 @@
+#include <gtest/gtest.h>
+#include <scratchcpp/value.h>
+
+#include "llvmtestutils.h"
+
+class LLVMStringEqualCaseSensitiveTest : public testing::Test
+{
+    public:
+        LLVMTestUtils m_utils;
+};
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, SameIntegers)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 10, 10);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, SameIntegers_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 10, 10);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentIntegers)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 10, 8);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentIntegers_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 10, 8);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentIntegersReversed)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 8, 10);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentIntegersReversed_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 8, 10);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, SameDecimals)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, -4.25, -4.25);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, SameDecimals_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, -4.25, -4.25);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentDecimals)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, -4.25, 5.312);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentDecimals_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, -4.25, 5.312);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentDecimalsReversed)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 5.312, -4.25);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentDecimalsReversed_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 5.312, -4.25);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, SameBooleans)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, true, true);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, SameBooleans_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, true, true);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentBooleans)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, true, false);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentBooleans_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, true, false);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentBooleansReversed)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, false, true);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentBooleansReversed_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, false, true);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NumberWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 1, true);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NumberWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 1, true);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NumberWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 1, false);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NumberWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 1, false);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, SameStrings)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "abC def", "abC def");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, SameStrings_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "abC def", "abC def");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, StringsCaseDifferent)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "abC def", "abc dEf");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, StringsCaseDifferent_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "abC def", "abc dEf");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentStrings)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "abC def", "ghi Jkl");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentStrings_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "abC def", "ghi Jkl");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentStringsLonger)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "abC def", "hello world");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentStringsLonger_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "abC def", "hello world");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, SpaceVsEmpty)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, " ", "");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, SpaceVsEmpty_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, " ", "");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, SpaceVsZeroString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, " ", "0");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, SpaceVsZeroString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, " ", "0");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, SpaceVsZeroNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, " ", 0);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, SpaceVsZeroNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, " ", 0);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroNumberVsSpace)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 0, " ");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroNumberVsSpace_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 0, " ");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, EmptyVsZeroString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "", "0");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, EmptyVsZeroString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "", "0");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, EmptyVsZeroNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "", 0);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, EmptyVsZeroNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "", 0);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroNumberVsEmpty)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 0, "");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroNumberVsEmpty_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 0, "");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroStringVsZeroNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "0", 0);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroStringVsZeroNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "0", 0);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroNumberVsZeroString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 0, "0");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroNumberVsZeroString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 0, "0");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NumberVsExactString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 5.25, "5.25");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NumberVsExactString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 5.25, "5.25");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, ExactStringVsNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "5.25", 5.25);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, ExactStringVsNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "5.25", 5.25);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NumberVsStringWithLeadingSpace)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 5.25, " 5.25");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NumberVsStringWithLeadingSpace_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 5.25, " 5.25");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, StringWithLeadingSpaceVsNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, " 5.25", 5.25);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, StringWithLeadingSpaceVsNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, " 5.25", 5.25);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NumberVsStringWithTrailingSpace)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 5.25, "5.25 ");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NumberVsStringWithTrailingSpace_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 5.25, "5.25 ");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, StringWithTrailingSpaceVsNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "5.25 ", 5.25);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, StringWithTrailingSpaceVsNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "5.25 ", 5.25);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NumberVsStringWithSurroundingSpaces)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 5.25, " 5.25 ");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NumberVsStringWithSurroundingSpaces_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 5.25, " 5.25 ");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, StringWithSurroundingSpacesVsNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, " 5.25 ", 5.25);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, StringWithSurroundingSpacesVsNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, " 5.25 ", 5.25);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NumberVsDifferentString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 5.25, "5.26");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NumberVsDifferentString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 5.25, "5.26");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentStringVsNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "5.26", 5.25);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentStringVsNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "5.26", 5.25);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentStringNumbers)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "5.25", "5.26");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, DifferentStringNumbers_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "5.25", "5.26");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NumberVsStringWithTrailingSpaces)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 5, "5  ");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NumberVsStringWithTrailingSpaces_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 5, "5  ");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, StringWithTrailingSpacesVsNumber)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "5  ", 5);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, StringWithTrailingSpacesVsNumber_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "5  ", 5);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroVsOneString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 0, "1");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroVsOneString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 0, "1");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, OneStringVsZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "1", 0);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, OneStringVsZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "1", 0);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroVsTestString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 0, "test");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroVsTestString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 0, "test");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, TestStringVsZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "test", 0);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, TestStringVsZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "test", 0);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NaNWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "NaN", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NaNWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "NaN", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "Infinity", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "Infinity", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NaNWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "NaN", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NaNWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "NaN", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "-Infinity", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "-Infinity", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NaNWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "NaN", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NaNWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "NaN", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NumberWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 5, "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NumberWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 5, "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NumberWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 5, "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NumberWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 5, "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NumberWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 5, "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NumberWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 5, "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 0, "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 0, "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, TrueBooleanWithTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, true, "true");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, TrueBooleanWithTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, true, "true");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, TrueStringWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "true", true);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, TrueStringWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "true", true);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, FalseBooleanWithFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, false, "false");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, FalseBooleanWithFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, false, "false");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, FalseStringWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "false", false);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, FalseStringWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "false", false);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, FalseBooleanWithTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, false, "true");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, FalseBooleanWithTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, false, "true");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, TrueStringWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "true", false);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, TrueStringWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "true", false);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, TrueBooleanWithFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, true, "false");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, TrueBooleanWithFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, true, "false");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, FalseStringWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "false", true);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, FalseStringWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "false", true);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, TrueBooleanWithUppercaseTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, true, "TRUE");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, TrueBooleanWithUppercaseTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, true, "TRUE");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, UppercaseTrueStringWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "TRUE", true);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, UppercaseTrueStringWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "TRUE", true);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, FalseBooleanWithUppercaseFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, false, "FALSE");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, FalseBooleanWithUppercaseFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, false, "FALSE");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, UppercaseFalseStringWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "FALSE", false);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, UppercaseFalseStringWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "FALSE", false);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, TrueBooleanWithZeroPaddedOne)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, true, "00001");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, TrueBooleanWithZeroPaddedOne_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, true, "00001");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroPaddedOneWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "00001", true);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroPaddedOneWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "00001", true);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, TrueBooleanWithZeroPaddedZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, true, "00000");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, TrueBooleanWithZeroPaddedZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, true, "00000");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroPaddedZeroWithTrueBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "00000", true);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroPaddedZeroWithTrueBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "00000", true);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, FalseBooleanWithZeroPaddedZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, false, "00000");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, FalseBooleanWithZeroPaddedZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, false, "00000");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroPaddedZeroWithFalseBoolean)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "00000", false);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroPaddedZeroWithFalseBoolean_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "00000", false);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, TrueStringWithOne)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "true", 1);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, TrueStringWithOne_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "true", 1);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, OneWithTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 1, "true");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, OneWithTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 1, "true");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, TrueStringWithZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "true", 0);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, TrueStringWithZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "true", 0);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroWithTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 0, "true");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroWithTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 0, "true");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, FalseStringWithZero)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "false", 0);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, FalseStringWithZero_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "false", 0);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroWithFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 0, "false");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, ZeroWithFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 0, "false");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, FalseStringWithOne)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "false", 1);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, FalseStringWithOne_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "false", 1);
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, OneWithFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, 1, "false");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, OneWithFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, 1, "false");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, TrueStringWithUppercaseTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "true", "TRUE");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, TrueStringWithUppercaseTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "true", "TRUE");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, TrueStringWithUppercaseFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "true", "FALSE");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, TrueStringWithUppercaseFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "true", "FALSE");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, FalseStringWithUppercaseFalseString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "false", "FALSE");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, FalseStringWithUppercaseFalseString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "false", "FALSE");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, FalseStringWithUppercaseTrueString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "false", "TRUE");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, FalseStringWithUppercaseTrueString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "false", "TRUE");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, TrueBooleanWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, true, "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, TrueBooleanWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, true, "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, TrueBooleanWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, true, "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, TrueBooleanWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, true, "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, TrueBooleanWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, true, "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, TrueBooleanWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, true, "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, FalseBooleanWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, false, "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, FalseBooleanWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, false, "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, FalseBooleanWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, false, "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, FalseBooleanWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, false, "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, FalseBooleanWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, false, "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, FalseBooleanWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, false, "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "Infinity", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "Infinity", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "Infinity", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "Infinity", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseInfinityStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "infinity", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseInfinityStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "infinity", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseInfinityStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "infinity", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseInfinityStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "infinity", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseInfinityStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "infinity", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseInfinityStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "infinity", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "-Infinity", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "-Infinity", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "-Infinity", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "-Infinity", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseNegativeInfinityStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "-infinity", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseNegativeInfinityStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "-infinity", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseNegativeInfinityStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "-infinity", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseNegativeInfinityStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "-infinity", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseNegativeInfinityStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "-infinity", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseNegativeInfinityStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "-infinity", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NaNStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "NaN", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NaNStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "NaN", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NaNStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "NaN", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NaNStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "NaN", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NaNStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "NaN", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NaNStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "NaN", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseNaNStringWithInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "nan", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseNaNStringWithInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "nan", "Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseNaNStringWithNegativeInfinity)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "nan", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseNaNStringWithNegativeInfinity_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "nan", "-Infinity");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseNaNStringWithNaN)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "nan", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, LowercaseNaNStringWithNaN_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "nan", "NaN");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityWithStringAbc)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "Infinity", "abc");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityWithStringAbc_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "Infinity", "abc");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityWithStringSpace)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "Infinity", " ");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityWithStringSpace_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "Infinity", " ");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityWithEmptyString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "Infinity", "");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityWithEmptyString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "Infinity", "");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityWithZeroString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "Infinity", "0");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, InfinityWithZeroString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "Infinity", "0");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityWithStringAbc)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "-Infinity", "abc");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityWithStringAbc_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "-Infinity", "abc");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityWithStringSpace)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "-Infinity", " ");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityWithStringSpace_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "-Infinity", " ");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityWithEmptyString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "-Infinity", "");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityWithEmptyString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "-Infinity", "");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityWithZeroString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "-Infinity", "0");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NegativeInfinityWithZeroString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "-Infinity", "0");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NaNWithStringAbc)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "NaN", "abc");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NaNWithStringAbc_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "NaN", "abc");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NaNWithStringSpace)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "NaN", " ");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NaNWithStringSpace_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "NaN", " ");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NaNWithEmptyString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "NaN", "");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NaNWithEmptyString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "NaN", "");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NaNWithZeroString)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, false, "NaN", "0");
+}
+
+TEST_F(LLVMStringEqualCaseSensitiveTest, NaNWithZeroString_Const)
+{
+    ASSERT_BOOL_OP2(m_utils, LLVMTestUtils::OpType::StrCmpEQCS, true, "NaN", "0");
+}
diff --git a/test/llvm/operators/string/string_length_test.cpp b/test/llvm/operators/string/string_length_test.cpp
new file mode 100644
index 00000000..f0ce51d5
--- /dev/null
+++ b/test/llvm/operators/string/string_length_test.cpp
@@ -0,0 +1,50 @@
+#include <gtest/gtest.h>
+#include <scratchcpp/value.h>
+
+#include "llvmtestutils.h"
+
+class LLVMStringLengthTest : public testing::Test
+{
+    public:
+        LLVMTestUtils m_utils;
+};
+
+TEST_F(LLVMStringLengthTest, HelloWorld)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringLength, false, "Hello world").toDouble(), 11);
+}
+
+TEST_F(LLVMStringLengthTest, HelloWorld_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringLength, true, "Hello world").toDouble(), 11);
+}
+
+TEST_F(LLVMStringLengthTest, Abc)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringLength, false, "abc").toDouble(), 3);
+}
+
+TEST_F(LLVMStringLengthTest, Abc_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringLength, true, "abc").toDouble(), 3);
+}
+
+TEST_F(LLVMStringLengthTest, Abcdef)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringLength, false, "abcdef").toDouble(), 6);
+}
+
+TEST_F(LLVMStringLengthTest, Abcdef_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringLength, true, "abcdef").toDouble(), 6);
+}
+
+TEST_F(LLVMStringLengthTest, UnicodeString)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringLength, false, "ábč").toDouble(), 3);
+}
+
+TEST_F(LLVMStringLengthTest, UnicodeString_Const)
+{
+    ASSERT_EQ(m_utils.getOpResult(LLVMTestUtils::OpType::StringLength, true, "ábč").toDouble(), 3);
+}

From 65e2ed8d9c3a3a9ea846b23fe58954e4023901d2 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Sun, 3 Aug 2025 17:29:53 +0200
Subject: [PATCH 59/79] LLVMTestUtils: Properly test NaN values

---
 test/llvm/llvmtestutils.h | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/test/llvm/llvmtestutils.h b/test/llvm/llvmtestutils.h
index 8d864fcf..0f677ed3 100644
--- a/test/llvm/llvmtestutils.h
+++ b/test/llvm/llvmtestutils.h
@@ -5,8 +5,17 @@
 #include <targetmock.h>
 #include <randomgeneratormock.h>
 
-#define ASSERT_NUM_OP1(utils, type, rawArg, v) ASSERT_EQ(utils.getOpResult(type, rawArg, v).toDouble(), m_utils.getExpectedOpResult(type, v).toDouble());
-#define ASSERT_NUM_OP2(utils, type, rawArgs, v1, v2) ASSERT_EQ(utils.getOpResult(type, rawArgs, v1, v2).toDouble(), m_utils.getExpectedOpResult(type, v1, v2).toDouble());
+#define ASSERT_NUM_OP1(utils, type, rawArg, v)                                                                                                                                                         \
+    Value result = utils.getOpResult(type, rawArg, v);                                                                                                                                                 \
+    Value expected = utils.getExpectedOpResult(type, v);                                                                                                                                               \
+    ASSERT_EQ(result.isNaN(), expected.isNaN());                                                                                                                                                       \
+    ASSERT_EQ(result.toDouble(), expected.toDouble());
+
+#define ASSERT_NUM_OP2(utils, type, rawArgs, v1, v2)                                                                                                                                                   \
+    Value result = utils.getOpResult(type, rawArgs, v1, v2);                                                                                                                                           \
+    Value expected = utils.getExpectedOpResult(type, v1, v2);                                                                                                                                          \
+    ASSERT_EQ(result.isNaN(), expected.isNaN());                                                                                                                                                       \
+    ASSERT_EQ(result.toDouble(), expected.toDouble());
 
 #define ASSERT_BOOL_OP1(utils, type, rawArg, v) ASSERT_EQ(utils.getOpResult(type, rawArg, v).toBool(), m_utils.getExpectedOpResult(type, v).toBool());
 #define ASSERT_BOOL_OP2(utils, type, rawArgs, v1, v2) ASSERT_EQ(utils.getOpResult(type, rawArgs, v1, v2).toBool(), m_utils.getExpectedOpResult(type, v1, v2).toBool());

From ee32ec43353542774465824587dbd6669fda9712 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Sun, 3 Aug 2025 20:30:15 +0200
Subject: [PATCH 60/79] Do not pass IRBuilder to LLVMTypes

---
 src/engine/internal/llvm/llvmcodebuilder.cpp |  4 ++--
 src/engine/internal/llvm/llvmtypes.cpp       | 10 +++-------
 src/engine/internal/llvm/llvmtypes.h         |  4 ++--
 test/llvm/llvmexecutablecode_test.cpp        |  2 +-
 4 files changed, 8 insertions(+), 12 deletions(-)

diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp
index d6e246db..739d5806 100644
--- a/src/engine/internal/llvm/llvmcodebuilder.cpp
+++ b/src/engine/internal/llvm/llvmcodebuilder.cpp
@@ -1851,8 +1851,8 @@ void LLVMCodeBuilder::createProcedureCall(BlockPrototype *prototype, const Compi
 void LLVMCodeBuilder::initTypes()
 {
     llvm::PointerType *pointerType = llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0);
-    m_valueDataType = LLVMTypes::createValueDataType(&m_builder);
-    m_stringPtrType = LLVMTypes::createStringPtrType(&m_builder);
+    m_valueDataType = LLVMTypes::createValueDataType(m_llvmCtx);
+    m_stringPtrType = LLVMTypes::createStringPtrType(m_llvmCtx);
 }
 
 void LLVMCodeBuilder::createVariableMap()
diff --git a/src/engine/internal/llvm/llvmtypes.cpp b/src/engine/internal/llvm/llvmtypes.cpp
index 8c4e1e66..8d46440a 100644
--- a/src/engine/internal/llvm/llvmtypes.cpp
+++ b/src/engine/internal/llvm/llvmtypes.cpp
@@ -6,12 +6,10 @@
 
 using namespace libscratchcpp;
 
-llvm::StructType *LLVMTypes::createValueDataType(llvm::IRBuilder<> *builder)
+llvm::StructType *LLVMTypes::createValueDataType(llvm::LLVMContext &ctx)
 {
-    llvm::LLVMContext &ctx = builder->getContext();
-
     // Create the ValueData struct
-    llvm::Type *unionType = builder->getInt64Ty(); // 64 bits is the largest size
+    llvm::Type *unionType = llvm::Type::getInt64Ty(ctx); // 64 bits is the largest size
 
     llvm::Type *valueType = llvm::Type::getInt32Ty(ctx); // Assuming ValueType is a 32-bit enum
     llvm::Type *padding = llvm::Type::getInt32Ty(ctx);   // Padding for alignment
@@ -22,10 +20,8 @@ llvm::StructType *LLVMTypes::createValueDataType(llvm::IRBuilder<> *builder)
     return ret;
 }
 
-llvm::StructType *LLVMTypes::createStringPtrType(llvm::IRBuilder<> *builder)
+llvm::StructType *LLVMTypes::createStringPtrType(llvm::LLVMContext &ctx)
 {
-    llvm::LLVMContext &ctx = builder->getContext();
-
     // Create the StringPtr struct
     llvm::PointerType *pointerType = llvm::PointerType::get(llvm::Type::getInt8Ty(ctx), 0);
     llvm::Type *sizeType = llvm::Type::getInt64Ty(ctx);
diff --git a/src/engine/internal/llvm/llvmtypes.h b/src/engine/internal/llvm/llvmtypes.h
index 61c5f401..cbfefa60 100644
--- a/src/engine/internal/llvm/llvmtypes.h
+++ b/src/engine/internal/llvm/llvmtypes.h
@@ -17,8 +17,8 @@ namespace libscratchcpp
 class LLVMTypes
 {
     public:
-        static llvm::StructType *createValueDataType(llvm::IRBuilder<> *builder);
-        static llvm::StructType *createStringPtrType(llvm::IRBuilder<> *builder);
+        static llvm::StructType *createValueDataType(llvm::LLVMContext &ctx);
+        static llvm::StructType *createStringPtrType(llvm::LLVMContext &ctx);
 };
 
 } // namespace libscratchcpp
diff --git a/test/llvm/llvmexecutablecode_test.cpp b/test/llvm/llvmexecutablecode_test.cpp
index d792cfde..6dbc6d52 100644
--- a/test/llvm/llvmexecutablecode_test.cpp
+++ b/test/llvm/llvmexecutablecode_test.cpp
@@ -30,7 +30,7 @@ class LLVMExecutableCodeTest : public testing::Test
             m_module = m_ctx->module();
             m_llvmCtx = m_ctx->llvmCtx();
             m_builder = std::make_unique<llvm::IRBuilder<>>(*m_llvmCtx);
-            m_valueDataType = LLVMTypes::createValueDataType(m_builder.get());
+            m_valueDataType = LLVMTypes::createValueDataType(*m_llvmCtx);
             test_function(nullptr, nullptr, nullptr, nullptr, nullptr); // force dependency
 
             m_script = std::make_unique<Script>(&m_target, nullptr, &m_engine);

From ef69b9f20a4f511bab06c17394d4ac3b453f2675 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Sun, 3 Aug 2025 20:39:09 +0200
Subject: [PATCH 61/79] Store custom LLVM types in LLVMCompilerContext

---
 src/engine/internal/llvm/llvmcodebuilder.cpp  |  5 ++--
 .../internal/llvm/llvmcompilercontext.cpp     | 23 ++++++++++++++++---
 .../internal/llvm/llvmcompilercontext.h       |  7 ++++++
 test/llvm/llvmexecutablecode_test.cpp         |  2 +-
 4 files changed, 30 insertions(+), 7 deletions(-)

diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp
index 739d5806..4fee98f4 100644
--- a/src/engine/internal/llvm/llvmcodebuilder.cpp
+++ b/src/engine/internal/llvm/llvmcodebuilder.cpp
@@ -15,7 +15,6 @@
 #include "llvmconstantregister.h"
 #include "llvmifstatement.h"
 #include "llvmloop.h"
-#include "llvmtypes.h"
 #include "llvmloopscope.h"
 
 using namespace libscratchcpp;
@@ -1851,8 +1850,8 @@ void LLVMCodeBuilder::createProcedureCall(BlockPrototype *prototype, const Compi
 void LLVMCodeBuilder::initTypes()
 {
     llvm::PointerType *pointerType = llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0);
-    m_valueDataType = LLVMTypes::createValueDataType(m_llvmCtx);
-    m_stringPtrType = LLVMTypes::createStringPtrType(m_llvmCtx);
+    m_valueDataType = m_ctx->valueDataType();
+    m_stringPtrType = m_ctx->stringPtrType();
 }
 
 void LLVMCodeBuilder::createVariableMap()
diff --git a/src/engine/internal/llvm/llvmcompilercontext.cpp b/src/engine/internal/llvm/llvmcompilercontext.cpp
index 78fc85a3..f879f930 100644
--- a/src/engine/internal/llvm/llvmcompilercontext.cpp
+++ b/src/engine/internal/llvm/llvmcompilercontext.cpp
@@ -9,6 +9,7 @@
 
 #include "llvmcompilercontext.h"
 #include "llvmcoroutine.h"
+#include "llvmtypes.h"
 
 using namespace libscratchcpp;
 
@@ -18,10 +19,16 @@ LLVMCompilerContext::LLVMCompilerContext(IEngine *engine, Target *target) :
     m_module(std::make_unique<llvm::Module>(target ? target->name() : "", *m_llvmCtx)),
     m_llvmCtxPtr(m_llvmCtx.get()),
     m_modulePtr(m_module.get()),
-    m_jit((initTarget(), llvm::orc::LLJITBuilder().create())),
-    m_llvmCoroResumeFunction(createCoroResumeFunction()),
-    m_llvmCoroDestroyFunction(createCoroDestroyFunction())
+    m_jit((initTarget(), llvm::orc::LLJITBuilder().create()))
 {
+    // Create functions
+    m_llvmCoroResumeFunction = createCoroResumeFunction();
+    m_llvmCoroDestroyFunction = createCoroDestroyFunction();
+
+    // Create types
+    m_valueDataType = LLVMTypes::createValueDataType(*m_llvmCtx);
+    m_stringPtrType = LLVMTypes::createStringPtrType(*m_llvmCtx);
+
     if (!m_jit) {
         llvm::errs() << "error: failed to create JIT: " << toString(m_jit.takeError()) << "\n";
         return;
@@ -129,6 +136,16 @@ void LLVMCompilerContext::destroyCoroutine(void *handle)
     m_coroDestroyFunction(handle);
 }
 
+llvm::StructType *LLVMCompilerContext::valueDataType() const
+{
+    return m_valueDataType;
+}
+
+llvm::StructType *LLVMCompilerContext::stringPtrType() const
+{
+    return m_stringPtrType;
+}
+
 void LLVMCompilerContext::initTarget()
 {
     llvm::InitializeNativeTarget();
diff --git a/src/engine/internal/llvm/llvmcompilercontext.h b/src/engine/internal/llvm/llvmcompilercontext.h
index 21ae681a..637e4961 100644
--- a/src/engine/internal/llvm/llvmcompilercontext.h
+++ b/src/engine/internal/llvm/llvmcompilercontext.h
@@ -31,6 +31,9 @@ class LLVMCompilerContext : public CompilerContext
         llvm::Function *coroutineResumeFunction() const;
         void destroyCoroutine(void *handle);
 
+        llvm::StructType *valueDataType() const;
+        llvm::StructType *stringPtrType() const;
+
         template<typename T>
         T lookupFunction(const std::string &name)
         {
@@ -49,6 +52,7 @@ class LLVMCompilerContext : public CompilerContext
         using DestroyCoroFuncType = void (*)(void *);
 
         void initTarget();
+
         llvm::Function *createCoroResumeFunction();
         llvm::Function *createCoroDestroyFunction();
 
@@ -65,6 +69,9 @@ class LLVMCompilerContext : public CompilerContext
 
         llvm::Function *m_llvmCoroDestroyFunction = nullptr;
         DestroyCoroFuncType m_coroDestroyFunction = nullptr;
+
+        llvm::StructType *m_valueDataType = nullptr;
+        llvm::StructType *m_stringPtrType = nullptr;
 };
 
 } // namespace libscratchcpp
diff --git a/test/llvm/llvmexecutablecode_test.cpp b/test/llvm/llvmexecutablecode_test.cpp
index 6dbc6d52..055efa48 100644
--- a/test/llvm/llvmexecutablecode_test.cpp
+++ b/test/llvm/llvmexecutablecode_test.cpp
@@ -30,7 +30,7 @@ class LLVMExecutableCodeTest : public testing::Test
             m_module = m_ctx->module();
             m_llvmCtx = m_ctx->llvmCtx();
             m_builder = std::make_unique<llvm::IRBuilder<>>(*m_llvmCtx);
-            m_valueDataType = LLVMTypes::createValueDataType(*m_llvmCtx);
+            m_valueDataType = m_ctx->valueDataType();
             test_function(nullptr, nullptr, nullptr, nullptr, nullptr); // force dependency
 
             m_script = std::make_unique<Script>(&m_target, nullptr, &m_engine);

From baa343529519f04c13526e2f89a80c8bf27ebab2 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Mon, 4 Aug 2025 10:17:54 +0200
Subject: [PATCH 62/79] Move external function resolve methods to a new class

---
 src/engine/internal/llvm/CMakeLists.txt      |   1 +
 src/engine/internal/llvm/llvmcodebuilder.cpp | 323 +++----------------
 src/engine/internal/llvm/llvmcodebuilder.h   |  40 +--
 src/engine/internal/llvm/llvmfunctions.cpp   | 264 ++++++++++++++-
 src/engine/internal/llvm/llvmfunctions.h     |  64 ++++
 5 files changed, 366 insertions(+), 326 deletions(-)
 create mode 100644 src/engine/internal/llvm/llvmfunctions.h

diff --git a/src/engine/internal/llvm/CMakeLists.txt b/src/engine/internal/llvm/CMakeLists.txt
index afdcee56..f0a3259b 100644
--- a/src/engine/internal/llvm/CMakeLists.txt
+++ b/src/engine/internal/llvm/CMakeLists.txt
@@ -16,6 +16,7 @@ target_sources(scratchcpp
     llvmtypes.cpp
     llvmtypes.h
     llvmfunctions.cpp
+    llvmfunctions.h
     llvmloopscope.h
     llvmtypeanalyzer.cpp
     llvmtypeanalyzer.h
diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp
index 4fee98f4..b0e8ca63 100644
--- a/src/engine/internal/llvm/llvmcodebuilder.cpp
+++ b/src/engine/internal/llvm/llvmcodebuilder.cpp
@@ -35,6 +35,7 @@ LLVMCodeBuilder::LLVMCodeBuilder(LLVMCompilerContext *ctx, BlockPrototype *proce
     m_llvmCtx(*ctx->llvmCtx()),
     m_module(ctx->module()),
     m_builder(m_llvmCtx),
+    m_functions(ctx, &m_builder),
     m_procedurePrototype(procedurePrototype),
     m_defaultWarp(procedurePrototype ? procedurePrototype->warp() : false),
     m_warp(m_defaultWarp),
@@ -139,10 +140,10 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
         listPtr.ptr = getListPtr(targetLists, list);
 
         listPtr.dataPtr = m_builder.CreateAlloca(m_valueDataType->getPointerTo()->getPointerTo());
-        m_builder.CreateStore(m_builder.CreateCall(resolve_list_data_ptr(), listPtr.ptr), listPtr.dataPtr);
+        m_builder.CreateStore(m_builder.CreateCall(m_functions.resolve_list_data_ptr(), listPtr.ptr), listPtr.dataPtr);
 
-        listPtr.sizePtr = m_builder.CreateCall(resolve_list_size_ptr(), listPtr.ptr);
-        listPtr.allocatedSizePtr = m_builder.CreateCall(resolve_list_alloc_size_ptr(), listPtr.ptr);
+        listPtr.sizePtr = m_builder.CreateCall(m_functions.resolve_list_size_ptr(), listPtr.ptr);
+        listPtr.allocatedSizePtr = m_builder.CreateCall(m_functions.resolve_list_alloc_size_ptr(), listPtr.ptr);
     }
 
     assert(m_loopScope == -1);
@@ -180,7 +181,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 }
 
                 llvm::Type *retType = getType(step.functionReturnReg ? step.functionReturnReg->type() : Compiler::StaticType::Void);
-                llvm::Value *ret = m_builder.CreateCall(resolveFunction(step.functionName, llvm::FunctionType::get(retType, types, false)), args);
+                llvm::Value *ret = m_builder.CreateCall(m_functions.resolveFunction(step.functionName, llvm::FunctionType::get(retType, types, false)), args);
 
                 if (step.functionReturnReg) {
                     step.functionReturnReg->value = ret;
@@ -242,7 +243,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 if (reg1->type() == Compiler::StaticType::Bool && reg2->type() == Compiler::StaticType::Bool) {
                     llvm::Value *bool1 = castValue(arg1.second, Compiler::StaticType::Bool);
                     llvm::Value *bool2 = castValue(arg2.second, Compiler::StaticType::Bool);
-                    step.functionReturnReg->value = m_builder.CreateCall(resolve_llvm_random_bool(), { executionContextPtr, bool1, bool2 });
+                    step.functionReturnReg->value = m_builder.CreateCall(m_functions.resolve_llvm_random_bool(), { executionContextPtr, bool1, bool2 });
                 } else {
                     llvm::Constant *inf = llvm::ConstantFP::getInfinity(m_builder.getDoubleTy(), false);
                     llvm::Value *num1 = removeNaN(castValue(arg1.second, Compiler::StaticType::Number));
@@ -253,11 +254,11 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
                     // NOTE: The random function will be called even in edge cases where it isn't needed, but they're rare, so it shouldn't be an issue
                     if (reg1->type() == Compiler::StaticType::Number && reg2->type() == Compiler::StaticType::Number)
-                        step.functionReturnReg->value = m_builder.CreateSelect(isInfOrNaN, sum, m_builder.CreateCall(resolve_llvm_random_double(), { executionContextPtr, num1, num2 }));
+                        step.functionReturnReg->value = m_builder.CreateSelect(isInfOrNaN, sum, m_builder.CreateCall(m_functions.resolve_llvm_random_double(), { executionContextPtr, num1, num2 }));
                     else {
                         llvm::Value *value1 = createValue(reg1);
                         llvm::Value *value2 = createValue(reg2);
-                        step.functionReturnReg->value = m_builder.CreateSelect(isInfOrNaN, sum, m_builder.CreateCall(resolve_llvm_random(), { executionContextPtr, value1, value2 }));
+                        step.functionReturnReg->value = m_builder.CreateSelect(isInfOrNaN, sum, m_builder.CreateCall(m_functions.resolve_llvm_random(), { executionContextPtr, value1, value2 }));
                     }
                 }
 
@@ -270,7 +271,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 const auto &arg2 = step.args[1];
                 llvm::Value *from = m_builder.CreateFPToSI(castValue(arg1.second, arg1.first), m_builder.getInt64Ty());
                 llvm::Value *to = m_builder.CreateFPToSI(castValue(arg2.second, arg2.first), m_builder.getInt64Ty());
-                step.functionReturnReg->value = m_builder.CreateCall(resolve_llvm_random_long(), { executionContextPtr, from, to });
+                step.functionReturnReg->value = m_builder.CreateCall(m_functions.resolve_llvm_random_long(), { executionContextPtr, from, to });
                 break;
             }
 
@@ -566,7 +567,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Function *memcpyFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::memcpy_inline, { charPointerType, charPointerType, m_builder.getInt64Ty() });
 
                 // StringPtr *result = string_pool_new(true)
-                llvm::Value *result = m_builder.CreateCall(resolve_string_pool_new(), m_builder.getInt1(true));
+                llvm::Value *result = m_builder.CreateCall(m_functions.resolve_string_pool_new(), m_builder.getInt1(true));
                 freeStringLater(result);
 
                 // result->size = string1->size + string2->size
@@ -579,7 +580,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 m_builder.CreateStore(resultSize, resultSizeField);
 
                 // string_alloc(result, result->size)
-                m_builder.CreateCall(resolve_string_alloc(), { result, resultSize });
+                m_builder.CreateCall(m_functions.resolve_string_alloc(), { result, resultSize });
 
                 // memcpy(result->data, string1->data, string1->size * sizeof(char16_t))
                 llvm::Value *dataField1 = m_builder.CreateStructGEP(m_stringPtrType, str1, 0);
@@ -618,9 +619,9 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Value *charPtr = m_builder.CreateGEP(m_builder.getInt16Ty(), data, index);
 
                 // Allocate string
-                llvm::Value *result = m_builder.CreateCall(resolve_string_pool_new(), m_builder.getInt1(true));
+                llvm::Value *result = m_builder.CreateCall(m_functions.resolve_string_pool_new(), m_builder.getInt1(true));
                 freeStringLater(result);
-                m_builder.CreateCall(resolve_string_alloc(), { result, m_builder.getInt64(1) }); // size 1 to avoid branching
+                m_builder.CreateCall(m_functions.resolve_string_alloc(), { result, m_builder.getInt64(1) }); // size 1 to avoid branching
 
                 // Get result data ptr
                 dataField = m_builder.CreateStructGEP(m_stringPtrType, result, 0);
@@ -786,7 +787,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
             case LLVMInstruction::Type::ClearList: {
                 assert(step.args.size() == 0);
                 LLVMListPtr &listPtr = m_listPtrs[step.workList];
-                m_builder.CreateCall(resolve_list_clear(), listPtr.ptr);
+                m_builder.CreateCall(m_functions.resolve_list_clear(), listPtr.ptr);
                 break;
             }
 
@@ -808,7 +809,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 // Remove
                 m_builder.SetInsertPoint(removeBlock);
                 index = m_builder.CreateFPToUI(castValue(arg.second, arg.first), m_builder.getInt64Ty());
-                m_builder.CreateCall(resolve_list_remove(), { listPtr.ptr, index });
+                m_builder.CreateCall(m_functions.resolve_list_remove(), { listPtr.ptr, index });
                 m_builder.CreateBr(nextBlock);
 
                 m_builder.SetInsertPoint(nextBlock);
@@ -844,7 +845,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
                 // Otherwise call appendEmpty()
                 m_builder.SetInsertPoint(elseBlock);
-                itemPtr = m_builder.CreateCall(resolve_list_append_empty(), listPtr.ptr);
+                itemPtr = m_builder.CreateCall(m_functions.resolve_list_append_empty(), listPtr.ptr);
                 createReusedValueStore(arg.second, itemPtr, type, listType);
                 m_builder.CreateBr(nextBlock);
 
@@ -878,7 +879,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 // Insert
                 m_builder.SetInsertPoint(insertBlock);
                 index = m_builder.CreateFPToUI(index, m_builder.getInt64Ty());
-                llvm::Value *itemPtr = m_builder.CreateCall(resolve_list_insert_empty(), { listPtr.ptr, index });
+                llvm::Value *itemPtr = m_builder.CreateCall(m_functions.resolve_list_insert_empty(), { listPtr.ptr, index });
                 createReusedValueStore(valueArg.second, itemPtr, type, listType);
 
                 m_builder.CreateBr(nextBlock);
@@ -923,7 +924,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
             case LLVMInstruction::Type::GetListContents: {
                 assert(step.args.size() == 0);
                 const LLVMListPtr &listPtr = m_listPtrs[step.workList];
-                llvm::Value *ptr = m_builder.CreateCall(resolve_list_to_string(), listPtr.ptr);
+                llvm::Value *ptr = m_builder.CreateCall(m_functions.resolve_list_to_string(), listPtr.ptr);
                 freeStringLater(ptr);
                 step.functionReturnReg->value = ptr;
                 break;
@@ -1240,7 +1241,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                         args.push_back(castValue(arg.second, arg.first));
                 }
 
-                llvm::Value *handle = m_builder.CreateCall(resolveFunction(name, type), args);
+                llvm::Value *handle = m_builder.CreateCall(m_functions.resolveFunction(name, type), args);
 
                 if (!m_warp && !step.procedurePrototype->warp()) {
                     llvm::BasicBlock *suspendBranch = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
@@ -2069,7 +2070,7 @@ void LLVMCodeBuilder::freeScopeHeap()
     auto &heap = m_stringHeap.back();
 
     for (llvm::Value *ptr : heap)
-        m_builder.CreateCall(resolve_string_pool_free(), { ptr });
+        m_builder.CreateCall(m_functions.resolve_string_pool_free(), { ptr });
 
     heap.clear();
 }
@@ -2107,7 +2108,7 @@ llvm::Value *LLVMCodeBuilder::castValue(LLVMRegister *reg, Compiler::StaticType
                 case Compiler::StaticType::String:
                 case Compiler::StaticType::Unknown: {
                     // Convert to double
-                    return m_builder.CreateCall(resolve_value_toDouble(), reg->value);
+                    return m_builder.CreateCall(m_functions.resolve_value_toDouble(), reg->value);
                 }
 
                 default:
@@ -2133,7 +2134,7 @@ llvm::Value *LLVMCodeBuilder::castValue(LLVMRegister *reg, Compiler::StaticType
                 case Compiler::StaticType::String:
                 case Compiler::StaticType::Unknown:
                     // Convert to bool
-                    return m_builder.CreateCall(resolve_value_toBool(), reg->value);
+                    return m_builder.CreateCall(m_functions.resolve_value_toBool(), reg->value);
 
                 default:
                     assert(false);
@@ -2147,7 +2148,7 @@ llvm::Value *LLVMCodeBuilder::castValue(LLVMRegister *reg, Compiler::StaticType
                 case Compiler::StaticType::Unknown: {
                     // Cast to string
                     // TODO: Use value_stringToDouble() and value_stringToBool()
-                    llvm::Value *ptr = m_builder.CreateCall(resolve_value_toStringPtr(), reg->value);
+                    llvm::Value *ptr = m_builder.CreateCall(m_functions.resolve_value_toStringPtr(), reg->value);
                     freeStringLater(ptr);
                     return ptr;
                 }
@@ -2186,7 +2187,7 @@ llvm::Value *LLVMCodeBuilder::castRawValue(LLVMRegister *reg, Compiler::StaticTy
 
                 case Compiler::StaticType::String: {
                     // Convert string to double
-                    return m_builder.CreateCall(resolve_value_stringToDouble(), reg->value);
+                    return m_builder.CreateCall(m_functions.resolve_value_stringToDouble(), reg->value);
                 }
 
                 default:
@@ -2202,7 +2203,7 @@ llvm::Value *LLVMCodeBuilder::castRawValue(LLVMRegister *reg, Compiler::StaticTy
 
                 case Compiler::StaticType::String:
                     // Convert string to bool
-                    return m_builder.CreateCall(resolve_value_stringToBool(), reg->value);
+                    return m_builder.CreateCall(m_functions.resolve_value_stringToBool(), reg->value);
 
                 default:
                     assert(false);
@@ -2213,14 +2214,14 @@ llvm::Value *LLVMCodeBuilder::castRawValue(LLVMRegister *reg, Compiler::StaticTy
             switch (reg->type()) {
                 case Compiler::StaticType::Number: {
                     // Convert double to string
-                    llvm::Value *ptr = m_builder.CreateCall(resolve_value_doubleToStringPtr(), reg->value);
+                    llvm::Value *ptr = m_builder.CreateCall(m_functions.resolve_value_doubleToStringPtr(), reg->value);
                     freeStringLater(ptr);
                     return ptr;
                 }
 
                 case Compiler::StaticType::Bool: {
                     // Convert bool to string
-                    llvm::Value *ptr = m_builder.CreateCall(resolve_value_boolToStringPtr(), reg->value);
+                    llvm::Value *ptr = m_builder.CreateCall(m_functions.resolve_value_boolToStringPtr(), reg->value);
                     // NOTE: Dot not deallocate later
                     return ptr;
                 }
@@ -2463,7 +2464,7 @@ void LLVMCodeBuilder::createValueStore(LLVMRegister *reg, llvm::Value *targetPtr
                 }
 
                 default:
-                    m_builder.CreateCall(resolve_value_assign_double(), { targetPtr, converted });
+                    m_builder.CreateCall(m_functions.resolve_value_assign_double(), { targetPtr, converted });
                     break;
             }
 
@@ -2489,18 +2490,18 @@ void LLVMCodeBuilder::createValueStore(LLVMRegister *reg, llvm::Value *targetPtr
                 }
 
                 default:
-                    m_builder.CreateCall(resolve_value_assign_bool(), { targetPtr, converted });
+                    m_builder.CreateCall(m_functions.resolve_value_assign_bool(), { targetPtr, converted });
                     break;
             }
 
             break;
 
         case Compiler::StaticType::String:
-            m_builder.CreateCall(resolve_value_assign_stringPtr(), { targetPtr, converted });
+            m_builder.CreateCall(m_functions.resolve_value_assign_stringPtr(), { targetPtr, converted });
             break;
 
         case Compiler::StaticType::Unknown:
-            m_builder.CreateCall(resolve_value_assign_copy(), { targetPtr, reg->value });
+            m_builder.CreateCall(m_functions.resolve_value_assign_copy(), { targetPtr, reg->value });
             break;
 
         default:
@@ -2658,8 +2659,8 @@ llvm::Value *LLVMCodeBuilder::createNewValue(LLVMRegister *reg)
     // NOTE: It is the caller's responsibility to free the value.
     llvm::Value *value = createValue(reg);
     llvm::Value *ret = addAlloca(m_valueDataType);
-    m_builder.CreateCall(resolve_value_init(), { ret });
-    m_builder.CreateCall(resolve_value_assign_copy(), { ret, value });
+    m_builder.CreateCall(m_functions.resolve_value_init(), { ret });
+    m_builder.CreateCall(m_functions.resolve_value_assign_copy(), { ret, value });
     return ret;
 }
 
@@ -2728,13 +2729,13 @@ llvm::Value *LLVMCodeBuilder::createComparison(LLVMRegister *arg1, LLVMRegister
 
             switch (type) {
                 case Comparison::EQ:
-                    return m_builder.CreateCall(resolve_value_equals(), { value1, value2 });
+                    return m_builder.CreateCall(m_functions.resolve_value_equals(), { value1, value2 });
 
                 case Comparison::GT:
-                    return m_builder.CreateCall(resolve_value_greater(), { value1, value2 });
+                    return m_builder.CreateCall(m_functions.resolve_value_greater(), { value1, value2 });
 
                 case Comparison::LT:
-                    return m_builder.CreateCall(resolve_value_lower(), { value1, value2 });
+                    return m_builder.CreateCall(m_functions.resolve_value_lower(), { value1, value2 });
 
                 default:
                     assert(false);
@@ -2823,7 +2824,7 @@ llvm::Value *LLVMCodeBuilder::createComparison(LLVMRegister *arg1, LLVMRegister
 
                 case Compiler::StaticType::String: {
                     // Compare two strings
-                    llvm::Value *cmpRet = m_builder.CreateCall(resolve_string_compare_case_insensitive(), { value1, value2 });
+                    llvm::Value *cmpRet = m_builder.CreateCall(m_functions.resolve_string_compare_case_insensitive(), { value1, value2 });
 
                     switch (type) {
                         case Comparison::EQ:
@@ -2879,7 +2880,7 @@ llvm::Value *LLVMCodeBuilder::createStringComparison(LLVMRegister *arg1, LLVMReg
         // Explicitly cast to string
         llvm::Value *string1 = castValue(arg1, Compiler::StaticType::String);
         llvm::Value *string2 = castValue(arg2, Compiler::StaticType::String);
-        llvm::Value *cmp = m_builder.CreateCall(caseSensitive ? resolve_string_compare_case_sensitive() : resolve_string_compare_case_insensitive(), { string1, string2 });
+        llvm::Value *cmp = m_builder.CreateCall(caseSensitive ? m_functions.resolve_string_compare_case_sensitive() : m_functions.resolve_string_compare_case_insensitive(), { string1, string2 });
         return m_builder.CreateICmpEQ(cmp, m_builder.getInt32(0));
     }
 }
@@ -2906,251 +2907,3 @@ void LLVMCodeBuilder::createSuspend(LLVMCoroutine *coro, llvm::Value *warpArg, l
         }
     }
 }
-
-llvm::FunctionCallee LLVMCodeBuilder::resolveFunction(const std::string name, llvm::FunctionType *type)
-{
-    return m_module->getOrInsertFunction(name, type);
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_value_init()
-{
-    return resolveFunction("value_init", llvm::FunctionType::get(m_builder.getVoidTy(), m_valueDataType->getPointerTo(), false));
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_value_free()
-{
-    return resolveFunction("value_free", llvm::FunctionType::get(m_builder.getVoidTy(), m_valueDataType->getPointerTo(), false));
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_value_assign_long()
-{
-    return resolveFunction("value_assign_long", llvm::FunctionType::get(m_builder.getVoidTy(), { m_valueDataType->getPointerTo(), m_builder.getInt64Ty() }, false));
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_value_assign_double()
-{
-    return resolveFunction("value_assign_double", llvm::FunctionType::get(m_builder.getVoidTy(), { m_valueDataType->getPointerTo(), m_builder.getDoubleTy() }, false));
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_value_assign_bool()
-{
-    return resolveFunction("value_assign_bool", llvm::FunctionType::get(m_builder.getVoidTy(), { m_valueDataType->getPointerTo(), m_builder.getInt1Ty() }, false));
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_value_assign_stringPtr()
-{
-    return resolveFunction("value_assign_stringPtr", llvm::FunctionType::get(m_builder.getVoidTy(), { m_valueDataType->getPointerTo(), m_stringPtrType->getPointerTo() }, false));
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_value_assign_special()
-{
-    return resolveFunction("value_assign_special", llvm::FunctionType::get(m_builder.getVoidTy(), { m_valueDataType->getPointerTo(), m_builder.getInt32Ty() }, false));
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_value_assign_copy()
-{
-    return resolveFunction("value_assign_copy", llvm::FunctionType::get(m_builder.getVoidTy(), { m_valueDataType->getPointerTo(), m_valueDataType->getPointerTo() }, false));
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_value_toDouble()
-{
-    llvm::FunctionCallee callee = resolveFunction("value_toDouble", llvm::FunctionType::get(m_builder.getDoubleTy(), m_valueDataType->getPointerTo(), false));
-    llvm::Function *func = llvm::cast<llvm::Function>(callee.getCallee());
-    func->addFnAttr(llvm::Attribute::ReadOnly);
-    return callee;
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_value_toBool()
-{
-    llvm::FunctionCallee callee = resolveFunction("value_toBool", llvm::FunctionType::get(m_builder.getInt1Ty(), m_valueDataType->getPointerTo(), false));
-    llvm::Function *func = llvm::cast<llvm::Function>(callee.getCallee());
-    func->addFnAttr(llvm::Attribute::ReadOnly);
-    return callee;
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_value_toStringPtr()
-{
-    // NOTE: This function can't be marked read-only because it allocates on the heap
-    return resolveFunction("value_toStringPtr", llvm::FunctionType::get(m_stringPtrType->getPointerTo(), m_valueDataType->getPointerTo(), false));
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_value_doubleToStringPtr()
-{
-    // NOTE: This function can't be marked read-only because it allocates on the heap
-    return resolveFunction("value_doubleToStringPtr", llvm::FunctionType::get(m_stringPtrType->getPointerTo(), m_builder.getDoubleTy(), false));
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_value_boolToStringPtr()
-{
-    // NOTE: This function can be marked read-only because it does NOT allocate on the heap ("true" and "false" constants)
-    llvm::FunctionCallee callee = resolveFunction("value_boolToStringPtr", llvm::FunctionType::get(m_stringPtrType->getPointerTo(), m_builder.getInt1Ty(), false));
-    llvm::Function *func = llvm::cast<llvm::Function>(callee.getCallee());
-    func->addFnAttr(llvm::Attribute::ReadOnly);
-    return callee;
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_value_stringToDouble()
-{
-    llvm::FunctionCallee callee = resolveFunction("value_stringToDouble", llvm::FunctionType::get(m_builder.getDoubleTy(), llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0), false));
-    llvm::Function *func = llvm::cast<llvm::Function>(callee.getCallee());
-    func->addFnAttr(llvm::Attribute::ReadOnly);
-    return callee;
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_value_stringToBool()
-{
-    llvm::FunctionCallee callee = resolveFunction("value_stringToBool", llvm::FunctionType::get(m_builder.getInt1Ty(), llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0), false));
-    llvm::Function *func = llvm::cast<llvm::Function>(callee.getCallee());
-    func->addFnAttr(llvm::Attribute::ReadOnly);
-    return callee;
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_value_equals()
-{
-    llvm::Type *valuePtr = m_valueDataType->getPointerTo();
-    llvm::FunctionCallee callee = resolveFunction("value_equals", llvm::FunctionType::get(m_builder.getInt1Ty(), { valuePtr, valuePtr }, false));
-    llvm::Function *func = llvm::cast<llvm::Function>(callee.getCallee());
-    func->addFnAttr(llvm::Attribute::ReadOnly);
-    return callee;
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_value_greater()
-{
-    llvm::Type *valuePtr = m_valueDataType->getPointerTo();
-    llvm::FunctionCallee callee = resolveFunction("value_greater", llvm::FunctionType::get(m_builder.getInt1Ty(), { valuePtr, valuePtr }, false));
-    llvm::Function *func = llvm::cast<llvm::Function>(callee.getCallee());
-    func->addFnAttr(llvm::Attribute::ReadOnly);
-    return callee;
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_value_lower()
-{
-    llvm::Type *valuePtr = m_valueDataType->getPointerTo();
-    llvm::FunctionCallee callee = resolveFunction("value_lower", llvm::FunctionType::get(m_builder.getInt1Ty(), { valuePtr, valuePtr }, false));
-    llvm::Function *func = llvm::cast<llvm::Function>(callee.getCallee());
-    func->addFnAttr(llvm::Attribute::ReadOnly);
-    return callee;
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_list_clear()
-{
-    llvm::Type *listPtr = llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0);
-    return resolveFunction("list_clear", llvm::FunctionType::get(m_builder.getVoidTy(), { listPtr }, false));
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_list_remove()
-{
-    llvm::Type *listPtr = llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0);
-    return resolveFunction("list_remove", llvm::FunctionType::get(m_builder.getVoidTy(), { listPtr, m_builder.getInt64Ty() }, false));
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_list_append_empty()
-{
-    llvm::Type *listPtr = llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0);
-    return resolveFunction("list_append_empty", llvm::FunctionType::get(m_valueDataType->getPointerTo(), { listPtr }, false));
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_list_insert_empty()
-{
-    llvm::Type *listPtr = llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0);
-    return resolveFunction("list_insert_empty", llvm::FunctionType::get(m_valueDataType->getPointerTo(), { listPtr, m_builder.getInt64Ty() }, false));
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_list_data_ptr()
-{
-    llvm::Type *listPtr = llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0);
-    llvm::FunctionCallee callee = resolveFunction("list_data_ptr", llvm::FunctionType::get(m_valueDataType->getPointerTo()->getPointerTo(), { listPtr }, false));
-    llvm::Function *func = llvm::cast<llvm::Function>(callee.getCallee());
-    func->addFnAttr(llvm::Attribute::ReadOnly);
-    return callee;
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_list_size_ptr()
-{
-    llvm::Type *listPtr = llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0);
-    llvm::FunctionCallee callee = resolveFunction("list_size_ptr", llvm::FunctionType::get(m_builder.getInt64Ty()->getPointerTo()->getPointerTo(), { listPtr }, false));
-    llvm::Function *func = llvm::cast<llvm::Function>(callee.getCallee());
-    func->addFnAttr(llvm::Attribute::ReadOnly);
-    return callee;
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_list_alloc_size_ptr()
-{
-    llvm::Type *listPtr = llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0);
-    llvm::FunctionCallee callee = resolveFunction("list_alloc_size_ptr", llvm::FunctionType::get(m_builder.getInt64Ty()->getPointerTo()->getPointerTo(), { listPtr }, false));
-    llvm::Function *func = llvm::cast<llvm::Function>(callee.getCallee());
-    func->addFnAttr(llvm::Attribute::ReadOnly);
-    return callee;
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_list_to_string()
-{
-    llvm::Type *pointerType = llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0);
-    llvm::FunctionCallee callee = resolveFunction("list_to_string", llvm::FunctionType::get(m_stringPtrType->getPointerTo(), { pointerType }, false));
-    llvm::Function *func = llvm::cast<llvm::Function>(callee.getCallee());
-    func->addFnAttr(llvm::Attribute::ReadOnly);
-    return callee;
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_llvm_random()
-{
-    llvm::Type *pointerType = llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0);
-    llvm::Type *valuePtr = m_valueDataType->getPointerTo();
-    return resolveFunction("llvm_random", llvm::FunctionType::get(m_builder.getDoubleTy(), { pointerType, valuePtr, valuePtr }, false));
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_llvm_random_double()
-{
-    llvm::Type *pointerType = llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0);
-    return resolveFunction("llvm_random_double", llvm::FunctionType::get(m_builder.getDoubleTy(), { pointerType, m_builder.getDoubleTy(), m_builder.getDoubleTy() }, false));
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_llvm_random_long()
-{
-    llvm::Type *pointerType = llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0);
-    return resolveFunction("llvm_random_long", llvm::FunctionType::get(m_builder.getDoubleTy(), { pointerType, m_builder.getInt64Ty(), m_builder.getInt64Ty() }, false));
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_llvm_random_bool()
-{
-    llvm::Type *pointerType = llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0);
-    return resolveFunction("llvm_random_bool", llvm::FunctionType::get(m_builder.getDoubleTy(), { pointerType, m_builder.getInt1Ty(), m_builder.getInt1Ty() }, false));
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_string_pool_new()
-{
-    return resolveFunction("string_pool_new", llvm::FunctionType::get(m_stringPtrType->getPointerTo(), { m_builder.getInt1Ty() }, false));
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_string_pool_free()
-{
-    return resolveFunction("string_pool_free", llvm::FunctionType::get(m_builder.getVoidTy(), { m_stringPtrType->getPointerTo() }, false));
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_string_alloc()
-{
-    return resolveFunction("string_alloc", llvm::FunctionType::get(m_builder.getVoidTy(), { m_stringPtrType->getPointerTo(), m_builder.getInt64Ty() }, false));
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_string_assign()
-{
-    return resolveFunction("string_assign", llvm::FunctionType::get(m_builder.getVoidTy(), { m_stringPtrType->getPointerTo(), m_stringPtrType->getPointerTo() }, false));
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_string_compare_case_sensitive()
-{
-    llvm::Type *stringPtr = m_stringPtrType->getPointerTo();
-    llvm::FunctionCallee callee = resolveFunction("string_compare_case_sensitive", llvm::FunctionType::get(m_builder.getInt32Ty(), { stringPtr, stringPtr }, false));
-    llvm::Function *func = llvm::cast<llvm::Function>(callee.getCallee());
-    func->addFnAttr(llvm::Attribute::ReadOnly);
-    return callee;
-}
-
-llvm::FunctionCallee LLVMCodeBuilder::resolve_string_compare_case_insensitive()
-{
-    llvm::Type *stringPtr = m_stringPtrType->getPointerTo();
-    llvm::FunctionCallee callee = resolveFunction("string_compare_case_insensitive", llvm::FunctionType::get(m_builder.getInt32Ty(), { stringPtr, stringPtr }, false));
-    llvm::Function *func = llvm::cast<llvm::Function>(callee.getCallee());
-    func->addFnAttr(llvm::Attribute::ReadOnly);
-    return callee;
-}
diff --git a/src/engine/internal/llvm/llvmcodebuilder.h b/src/engine/internal/llvm/llvmcodebuilder.h
index ab641240..c89d9db3 100644
--- a/src/engine/internal/llvm/llvmcodebuilder.h
+++ b/src/engine/internal/llvm/llvmcodebuilder.h
@@ -16,6 +16,7 @@
 #include "llvmvariableptr.h"
 #include "llvmlistptr.h"
 #include "llvmtypeanalyzer.h"
+#include "llvmfunctions.h"
 
 namespace libscratchcpp
 {
@@ -173,44 +174,6 @@ class LLVMCodeBuilder : public ICodeBuilder
 
         void createSuspend(LLVMCoroutine *coro, llvm::Value *warpArg, llvm::Value *targetVariables);
 
-        llvm::FunctionCallee resolveFunction(const std::string name, llvm::FunctionType *type);
-        llvm::FunctionCallee resolve_value_init();
-        llvm::FunctionCallee resolve_value_free();
-        llvm::FunctionCallee resolve_value_assign_long();
-        llvm::FunctionCallee resolve_value_assign_double();
-        llvm::FunctionCallee resolve_value_assign_bool();
-        llvm::FunctionCallee resolve_value_assign_stringPtr();
-        llvm::FunctionCallee resolve_value_assign_special();
-        llvm::FunctionCallee resolve_value_assign_copy();
-        llvm::FunctionCallee resolve_value_toDouble();
-        llvm::FunctionCallee resolve_value_toBool();
-        llvm::FunctionCallee resolve_value_toStringPtr();
-        llvm::FunctionCallee resolve_value_doubleToStringPtr();
-        llvm::FunctionCallee resolve_value_boolToStringPtr();
-        llvm::FunctionCallee resolve_value_stringToDouble();
-        llvm::FunctionCallee resolve_value_stringToBool();
-        llvm::FunctionCallee resolve_value_equals();
-        llvm::FunctionCallee resolve_value_greater();
-        llvm::FunctionCallee resolve_value_lower();
-        llvm::FunctionCallee resolve_list_clear();
-        llvm::FunctionCallee resolve_list_remove();
-        llvm::FunctionCallee resolve_list_append_empty();
-        llvm::FunctionCallee resolve_list_insert_empty();
-        llvm::FunctionCallee resolve_list_data_ptr();
-        llvm::FunctionCallee resolve_list_size_ptr();
-        llvm::FunctionCallee resolve_list_alloc_size_ptr();
-        llvm::FunctionCallee resolve_list_to_string();
-        llvm::FunctionCallee resolve_llvm_random();
-        llvm::FunctionCallee resolve_llvm_random_double();
-        llvm::FunctionCallee resolve_llvm_random_long();
-        llvm::FunctionCallee resolve_llvm_random_bool();
-        llvm::FunctionCallee resolve_string_pool_new();
-        llvm::FunctionCallee resolve_string_pool_free();
-        llvm::FunctionCallee resolve_string_alloc();
-        llvm::FunctionCallee resolve_string_assign();
-        llvm::FunctionCallee resolve_string_compare_case_sensitive();
-        llvm::FunctionCallee resolve_string_compare_case_insensitive();
-
         Target *m_target = nullptr;
 
         std::unordered_map<Variable *, size_t> m_targetVariableMap;
@@ -224,6 +187,7 @@ class LLVMCodeBuilder : public ICodeBuilder
         llvm::Module *m_module = nullptr;
         llvm::IRBuilder<> m_builder;
         llvm::Function *m_function = nullptr;
+        LLVMFunctions m_functions;
         LLVMTypeAnalyzer m_typeAnalyzer;
 
         llvm::StructType *m_valueDataType = nullptr;
diff --git a/src/engine/internal/llvm/llvmfunctions.cpp b/src/engine/internal/llvm/llvmfunctions.cpp
index 0304382b..899254aa 100644
--- a/src/engine/internal/llvm/llvmfunctions.cpp
+++ b/src/engine/internal/llvm/llvmfunctions.cpp
@@ -4,8 +4,10 @@
 #include <scratchcpp/executioncontext.h>
 #include <scratchcpp/irandomgenerator.h>
 
-namespace libscratchcpp
-{
+#include "llvmfunctions.h"
+#include "llvmcompilercontext.h"
+
+using namespace libscratchcpp;
 
 extern "C"
 {
@@ -30,4 +32,260 @@ extern "C"
     }
 }
 
-} // namespace libscratchcpp
+LLVMFunctions::LLVMFunctions(LLVMCompilerContext *ctx, llvm::IRBuilder<> *builder) :
+    m_ctx(ctx),
+    m_builder(builder)
+{
+    // Custom types
+    m_stringPtrType = m_ctx->stringPtrType();
+    m_valueDataType = m_ctx->valueDataType();
+}
+
+llvm::FunctionCallee LLVMFunctions::resolveFunction(const std::string name, llvm::FunctionType *type)
+{
+    return m_ctx->module()->getOrInsertFunction(name, type);
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_value_init()
+{
+    return resolveFunction("value_init", llvm::FunctionType::get(m_builder->getVoidTy(), m_valueDataType->getPointerTo(), false));
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_value_free()
+{
+    return resolveFunction("value_free", llvm::FunctionType::get(m_builder->getVoidTy(), m_valueDataType->getPointerTo(), false));
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_value_assign_long()
+{
+    return resolveFunction("value_assign_long", llvm::FunctionType::get(m_builder->getVoidTy(), { m_valueDataType->getPointerTo(), m_builder->getInt64Ty() }, false));
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_value_assign_double()
+{
+    return resolveFunction("value_assign_double", llvm::FunctionType::get(m_builder->getVoidTy(), { m_valueDataType->getPointerTo(), m_builder->getDoubleTy() }, false));
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_value_assign_bool()
+{
+    return resolveFunction("value_assign_bool", llvm::FunctionType::get(m_builder->getVoidTy(), { m_valueDataType->getPointerTo(), m_builder->getInt1Ty() }, false));
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_value_assign_stringPtr()
+{
+    return resolveFunction("value_assign_stringPtr", llvm::FunctionType::get(m_builder->getVoidTy(), { m_valueDataType->getPointerTo(), m_stringPtrType->getPointerTo() }, false));
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_value_assign_special()
+{
+    return resolveFunction("value_assign_special", llvm::FunctionType::get(m_builder->getVoidTy(), { m_valueDataType->getPointerTo(), m_builder->getInt32Ty() }, false));
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_value_assign_copy()
+{
+    return resolveFunction("value_assign_copy", llvm::FunctionType::get(m_builder->getVoidTy(), { m_valueDataType->getPointerTo(), m_valueDataType->getPointerTo() }, false));
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_value_toDouble()
+{
+    llvm::FunctionCallee callee = resolveFunction("value_toDouble", llvm::FunctionType::get(m_builder->getDoubleTy(), m_valueDataType->getPointerTo(), false));
+    llvm::Function *func = llvm::cast<llvm::Function>(callee.getCallee());
+    func->addFnAttr(llvm::Attribute::ReadOnly);
+    return callee;
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_value_toBool()
+{
+    llvm::FunctionCallee callee = resolveFunction("value_toBool", llvm::FunctionType::get(m_builder->getInt1Ty(), m_valueDataType->getPointerTo(), false));
+    llvm::Function *func = llvm::cast<llvm::Function>(callee.getCallee());
+    func->addFnAttr(llvm::Attribute::ReadOnly);
+    return callee;
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_value_toStringPtr()
+{
+    // NOTE: This function can't be marked read-only because it allocates on the heap
+    return resolveFunction("value_toStringPtr", llvm::FunctionType::get(m_stringPtrType->getPointerTo(), m_valueDataType->getPointerTo(), false));
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_value_doubleToStringPtr()
+{
+    // NOTE: This function can't be marked read-only because it allocates on the heap
+    return resolveFunction("value_doubleToStringPtr", llvm::FunctionType::get(m_stringPtrType->getPointerTo(), m_builder->getDoubleTy(), false));
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_value_boolToStringPtr()
+{
+    // NOTE: This function can be marked read-only because it does NOT allocate on the heap ("true" and "false" constants)
+    llvm::FunctionCallee callee = resolveFunction("value_boolToStringPtr", llvm::FunctionType::get(m_stringPtrType->getPointerTo(), m_builder->getInt1Ty(), false));
+    llvm::Function *func = llvm::cast<llvm::Function>(callee.getCallee());
+    func->addFnAttr(llvm::Attribute::ReadOnly);
+    return callee;
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_value_stringToDouble()
+{
+    llvm::FunctionCallee callee =
+        resolveFunction("value_stringToDouble", llvm::FunctionType::get(m_builder->getDoubleTy(), llvm::PointerType::get(llvm::Type::getInt8Ty(*m_ctx->llvmCtx()), 0), false));
+    llvm::Function *func = llvm::cast<llvm::Function>(callee.getCallee());
+    func->addFnAttr(llvm::Attribute::ReadOnly);
+    return callee;
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_value_stringToBool()
+{
+    llvm::FunctionCallee callee = resolveFunction("value_stringToBool", llvm::FunctionType::get(m_builder->getInt1Ty(), llvm::PointerType::get(llvm::Type::getInt8Ty(*m_ctx->llvmCtx()), 0), false));
+    llvm::Function *func = llvm::cast<llvm::Function>(callee.getCallee());
+    func->addFnAttr(llvm::Attribute::ReadOnly);
+    return callee;
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_value_equals()
+{
+    llvm::Type *valuePtr = m_valueDataType->getPointerTo();
+    llvm::FunctionCallee callee = resolveFunction("value_equals", llvm::FunctionType::get(m_builder->getInt1Ty(), { valuePtr, valuePtr }, false));
+    llvm::Function *func = llvm::cast<llvm::Function>(callee.getCallee());
+    func->addFnAttr(llvm::Attribute::ReadOnly);
+    return callee;
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_value_greater()
+{
+    llvm::Type *valuePtr = m_valueDataType->getPointerTo();
+    llvm::FunctionCallee callee = resolveFunction("value_greater", llvm::FunctionType::get(m_builder->getInt1Ty(), { valuePtr, valuePtr }, false));
+    llvm::Function *func = llvm::cast<llvm::Function>(callee.getCallee());
+    func->addFnAttr(llvm::Attribute::ReadOnly);
+    return callee;
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_value_lower()
+{
+    llvm::Type *valuePtr = m_valueDataType->getPointerTo();
+    llvm::FunctionCallee callee = resolveFunction("value_lower", llvm::FunctionType::get(m_builder->getInt1Ty(), { valuePtr, valuePtr }, false));
+    llvm::Function *func = llvm::cast<llvm::Function>(callee.getCallee());
+    func->addFnAttr(llvm::Attribute::ReadOnly);
+    return callee;
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_list_clear()
+{
+    llvm::Type *listPtr = llvm::PointerType::get(llvm::Type::getInt8Ty(*m_ctx->llvmCtx()), 0);
+    return resolveFunction("list_clear", llvm::FunctionType::get(m_builder->getVoidTy(), { listPtr }, false));
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_list_remove()
+{
+    llvm::Type *listPtr = llvm::PointerType::get(llvm::Type::getInt8Ty(*m_ctx->llvmCtx()), 0);
+    return resolveFunction("list_remove", llvm::FunctionType::get(m_builder->getVoidTy(), { listPtr, m_builder->getInt64Ty() }, false));
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_list_append_empty()
+{
+    llvm::Type *listPtr = llvm::PointerType::get(llvm::Type::getInt8Ty(*m_ctx->llvmCtx()), 0);
+    return resolveFunction("list_append_empty", llvm::FunctionType::get(m_valueDataType->getPointerTo(), { listPtr }, false));
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_list_insert_empty()
+{
+    llvm::Type *listPtr = llvm::PointerType::get(llvm::Type::getInt8Ty(*m_ctx->llvmCtx()), 0);
+    return resolveFunction("list_insert_empty", llvm::FunctionType::get(m_valueDataType->getPointerTo(), { listPtr, m_builder->getInt64Ty() }, false));
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_list_data_ptr()
+{
+    llvm::Type *listPtr = llvm::PointerType::get(llvm::Type::getInt8Ty(*m_ctx->llvmCtx()), 0);
+    llvm::FunctionCallee callee = resolveFunction("list_data_ptr", llvm::FunctionType::get(m_valueDataType->getPointerTo()->getPointerTo(), { listPtr }, false));
+    llvm::Function *func = llvm::cast<llvm::Function>(callee.getCallee());
+    func->addFnAttr(llvm::Attribute::ReadOnly);
+    return callee;
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_list_size_ptr()
+{
+    llvm::Type *listPtr = llvm::PointerType::get(llvm::Type::getInt8Ty(*m_ctx->llvmCtx()), 0);
+    llvm::FunctionCallee callee = resolveFunction("list_size_ptr", llvm::FunctionType::get(m_builder->getInt64Ty()->getPointerTo()->getPointerTo(), { listPtr }, false));
+    llvm::Function *func = llvm::cast<llvm::Function>(callee.getCallee());
+    func->addFnAttr(llvm::Attribute::ReadOnly);
+    return callee;
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_list_alloc_size_ptr()
+{
+    llvm::Type *listPtr = llvm::PointerType::get(llvm::Type::getInt8Ty(*m_ctx->llvmCtx()), 0);
+    llvm::FunctionCallee callee = resolveFunction("list_alloc_size_ptr", llvm::FunctionType::get(m_builder->getInt64Ty()->getPointerTo()->getPointerTo(), { listPtr }, false));
+    llvm::Function *func = llvm::cast<llvm::Function>(callee.getCallee());
+    func->addFnAttr(llvm::Attribute::ReadOnly);
+    return callee;
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_list_to_string()
+{
+    llvm::Type *pointerType = llvm::PointerType::get(llvm::Type::getInt8Ty(*m_ctx->llvmCtx()), 0);
+    llvm::FunctionCallee callee = resolveFunction("list_to_string", llvm::FunctionType::get(m_stringPtrType->getPointerTo(), { pointerType }, false));
+    llvm::Function *func = llvm::cast<llvm::Function>(callee.getCallee());
+    func->addFnAttr(llvm::Attribute::ReadOnly);
+    return callee;
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_llvm_random()
+{
+    llvm::Type *pointerType = llvm::PointerType::get(llvm::Type::getInt8Ty(*m_ctx->llvmCtx()), 0);
+    llvm::Type *valuePtr = m_valueDataType->getPointerTo();
+    return resolveFunction("llvm_random", llvm::FunctionType::get(m_builder->getDoubleTy(), { pointerType, valuePtr, valuePtr }, false));
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_llvm_random_double()
+{
+    llvm::Type *pointerType = llvm::PointerType::get(llvm::Type::getInt8Ty(*m_ctx->llvmCtx()), 0);
+    return resolveFunction("llvm_random_double", llvm::FunctionType::get(m_builder->getDoubleTy(), { pointerType, m_builder->getDoubleTy(), m_builder->getDoubleTy() }, false));
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_llvm_random_long()
+{
+    llvm::Type *pointerType = llvm::PointerType::get(llvm::Type::getInt8Ty(*m_ctx->llvmCtx()), 0);
+    return resolveFunction("llvm_random_long", llvm::FunctionType::get(m_builder->getDoubleTy(), { pointerType, m_builder->getInt64Ty(), m_builder->getInt64Ty() }, false));
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_llvm_random_bool()
+{
+    llvm::Type *pointerType = llvm::PointerType::get(llvm::Type::getInt8Ty(*m_ctx->llvmCtx()), 0);
+    return resolveFunction("llvm_random_bool", llvm::FunctionType::get(m_builder->getDoubleTy(), { pointerType, m_builder->getInt1Ty(), m_builder->getInt1Ty() }, false));
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_string_pool_new()
+{
+    return resolveFunction("string_pool_new", llvm::FunctionType::get(m_stringPtrType->getPointerTo(), { m_builder->getInt1Ty() }, false));
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_string_pool_free()
+{
+    return resolveFunction("string_pool_free", llvm::FunctionType::get(m_builder->getVoidTy(), { m_stringPtrType->getPointerTo() }, false));
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_string_alloc()
+{
+    return resolveFunction("string_alloc", llvm::FunctionType::get(m_builder->getVoidTy(), { m_stringPtrType->getPointerTo(), m_builder->getInt64Ty() }, false));
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_string_assign()
+{
+    return resolveFunction("string_assign", llvm::FunctionType::get(m_builder->getVoidTy(), { m_stringPtrType->getPointerTo(), m_stringPtrType->getPointerTo() }, false));
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_string_compare_case_sensitive()
+{
+    llvm::Type *stringPtr = m_stringPtrType->getPointerTo();
+    llvm::FunctionCallee callee = resolveFunction("string_compare_case_sensitive", llvm::FunctionType::get(m_builder->getInt32Ty(), { stringPtr, stringPtr }, false));
+    llvm::Function *func = llvm::cast<llvm::Function>(callee.getCallee());
+    func->addFnAttr(llvm::Attribute::ReadOnly);
+    return callee;
+}
+
+llvm::FunctionCallee LLVMFunctions::resolve_string_compare_case_insensitive()
+{
+    llvm::Type *stringPtr = m_stringPtrType->getPointerTo();
+    llvm::FunctionCallee callee = resolveFunction("string_compare_case_insensitive", llvm::FunctionType::get(m_builder->getInt32Ty(), { stringPtr, stringPtr }, false));
+    llvm::Function *func = llvm::cast<llvm::Function>(callee.getCallee());
+    func->addFnAttr(llvm::Attribute::ReadOnly);
+    return callee;
+}
diff --git a/src/engine/internal/llvm/llvmfunctions.h b/src/engine/internal/llvm/llvmfunctions.h
new file mode 100644
index 00000000..2a257321
--- /dev/null
+++ b/src/engine/internal/llvm/llvmfunctions.h
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include <llvm/IR/IRBuilder.h>
+
+namespace libscratchcpp
+{
+
+class LLVMCompilerContext;
+
+class LLVMFunctions
+{
+    public:
+        LLVMFunctions(LLVMCompilerContext *ctx, llvm::IRBuilder<> *builder);
+
+        llvm::FunctionCallee resolveFunction(const std::string name, llvm::FunctionType *type);
+
+        llvm::FunctionCallee resolve_value_init();
+        llvm::FunctionCallee resolve_value_free();
+        llvm::FunctionCallee resolve_value_assign_long();
+        llvm::FunctionCallee resolve_value_assign_double();
+        llvm::FunctionCallee resolve_value_assign_bool();
+        llvm::FunctionCallee resolve_value_assign_stringPtr();
+        llvm::FunctionCallee resolve_value_assign_special();
+        llvm::FunctionCallee resolve_value_assign_copy();
+        llvm::FunctionCallee resolve_value_toDouble();
+        llvm::FunctionCallee resolve_value_toBool();
+        llvm::FunctionCallee resolve_value_toStringPtr();
+        llvm::FunctionCallee resolve_value_doubleToStringPtr();
+        llvm::FunctionCallee resolve_value_boolToStringPtr();
+        llvm::FunctionCallee resolve_value_stringToDouble();
+        llvm::FunctionCallee resolve_value_stringToBool();
+        llvm::FunctionCallee resolve_value_equals();
+        llvm::FunctionCallee resolve_value_greater();
+        llvm::FunctionCallee resolve_value_lower();
+        llvm::FunctionCallee resolve_list_clear();
+        llvm::FunctionCallee resolve_list_remove();
+        llvm::FunctionCallee resolve_list_append_empty();
+        llvm::FunctionCallee resolve_list_insert_empty();
+        llvm::FunctionCallee resolve_list_data_ptr();
+        llvm::FunctionCallee resolve_list_size_ptr();
+        llvm::FunctionCallee resolve_list_alloc_size_ptr();
+        llvm::FunctionCallee resolve_list_to_string();
+        llvm::FunctionCallee resolve_llvm_random();
+        llvm::FunctionCallee resolve_llvm_random_double();
+        llvm::FunctionCallee resolve_llvm_random_long();
+        llvm::FunctionCallee resolve_llvm_random_bool();
+        llvm::FunctionCallee resolve_string_pool_new();
+        llvm::FunctionCallee resolve_string_pool_free();
+        llvm::FunctionCallee resolve_string_alloc();
+        llvm::FunctionCallee resolve_string_assign();
+        llvm::FunctionCallee resolve_string_compare_case_sensitive();
+        llvm::FunctionCallee resolve_string_compare_case_insensitive();
+
+    private:
+        LLVMCompilerContext *m_ctx = nullptr;
+        llvm::IRBuilder<> *m_builder = nullptr;
+
+        llvm::StructType *m_stringPtrType = nullptr;
+        llvm::StructType *m_valueDataType = nullptr;
+};
+
+} // namespace libscratchcpp

From ba37c7f6464b0933e8007f20dab8ee5b76cced5e Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Mon, 4 Aug 2025 10:34:40 +0200
Subject: [PATCH 63/79] Drop LLVMLoopScope

It was used by the old type analysis algorithm.
---
 src/engine/internal/llvm/CMakeLists.txt       |    1 -
 src/engine/internal/llvm/llvmcodebuilder.cpp  |  128 +-
 src/engine/internal/llvm/llvmcodebuilder.h    |   10 -
 src/engine/internal/llvm/llvminstruction.h    |    5 +-
 src/engine/internal/llvm/llvmlistptr.h        |    5 -
 src/engine/internal/llvm/llvmloopscope.h      |   18 -
 src/engine/internal/llvm/llvmvariableptr.h    |    5 -
 test/llvm/llvminstructionlist_test.cpp        |  114 +-
 test/llvm/type_analyzer/listtype_test.cpp     | 1244 ++++++++---------
 .../listtypeafterbranch_test.cpp              |  794 +++++------
 test/llvm/type_analyzer/mixed_test.cpp        |  138 +-
 test/llvm/type_analyzer/variabletype_test.cpp |  742 +++++-----
 .../variabletypeafterbranch_test.cpp          |  722 +++++-----
 13 files changed, 1908 insertions(+), 2018 deletions(-)
 delete mode 100644 src/engine/internal/llvm/llvmloopscope.h

diff --git a/src/engine/internal/llvm/CMakeLists.txt b/src/engine/internal/llvm/CMakeLists.txt
index f0a3259b..18814476 100644
--- a/src/engine/internal/llvm/CMakeLists.txt
+++ b/src/engine/internal/llvm/CMakeLists.txt
@@ -17,7 +17,6 @@ target_sources(scratchcpp
     llvmtypes.h
     llvmfunctions.cpp
     llvmfunctions.h
-    llvmloopscope.h
     llvmtypeanalyzer.cpp
     llvmtypeanalyzer.h
     llvmcompilercontext.cpp
diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp
index b0e8ca63..1bc7d3e0 100644
--- a/src/engine/internal/llvm/llvmcodebuilder.cpp
+++ b/src/engine/internal/llvm/llvmcodebuilder.cpp
@@ -15,7 +15,6 @@
 #include "llvmconstantregister.h"
 #include "llvmifstatement.h"
 #include "llvmloop.h"
-#include "llvmloopscope.h"
 
 using namespace libscratchcpp;
 
@@ -124,8 +123,9 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
         // If there are no write operations outside loops, initialize the stack variable now
         Variable *variable = var;
+        // TODO: Loop scope was used here, replace it with some "inside loop" flag if needed
         auto it = std::find_if(m_variableInstructions.begin(), m_variableInstructions.end(), [variable](const LLVMInstruction *ins) {
-            return ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == variable && !ins->loopScope;
+            return ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == variable /*&& !ins->loopScope*/;
         });
 
         if (it == m_variableInstructions.end()) {
@@ -146,8 +146,6 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
         listPtr.allocatedSizePtr = m_builder.CreateCall(m_functions.resolve_list_alloc_size_ptr(), listPtr.ptr);
     }
 
-    assert(m_loopScope == -1);
-    m_loopScope = -1;
     pushScopeLevel();
 
     // Execute recorded steps
@@ -1116,7 +1114,6 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
                 loops.push_back(loop);
                 pushScopeLevel();
-                pushLoopScope(true);
                 break;
             }
 
@@ -1146,7 +1143,6 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 // Switch to body branch
                 m_builder.SetInsertPoint(body);
                 pushScopeLevel();
-                pushLoopScope(true);
                 break;
             }
 
@@ -1168,7 +1164,6 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 // Switch to body branch
                 m_builder.SetInsertPoint(body);
                 pushScopeLevel();
-                pushLoopScope(true);
                 break;
             }
 
@@ -1202,7 +1197,6 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
                 loops.pop_back();
                 popScopeLevel();
-                popLoopScope();
                 break;
             }
 
@@ -1316,7 +1310,7 @@ CompilerValue *LLVMCodeBuilder::addFunctionCall(const std::string &functionName,
 {
     assert(argTypes.size() == args.size());
 
-    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, currentLoopScope(), m_loopCondition);
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, m_loopCondition);
     ins->functionName = functionName;
 
     for (size_t i = 0; i < args.size(); i++)
@@ -1378,7 +1372,7 @@ CompilerValue *LLVMCodeBuilder::addLocalVariableValue(CompilerLocalVariable *var
 
 CompilerValue *LLVMCodeBuilder::addVariableValue(Variable *variable)
 {
-    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, currentLoopScope(), m_loopCondition);
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, m_loopCondition);
     ins->workVariable = variable;
 
     if (m_variablePtrs.find(variable) == m_variablePtrs.cend())
@@ -1395,7 +1389,7 @@ CompilerValue *LLVMCodeBuilder::addVariableValue(Variable *variable)
 
 CompilerValue *LLVMCodeBuilder::addListContents(List *list)
 {
-    LLVMInstruction ins(LLVMInstruction::Type::GetListContents, currentLoopScope(), m_loopCondition);
+    LLVMInstruction ins(LLVMInstruction::Type::GetListContents, m_loopCondition);
     ins.workList = list;
 
     if (m_listPtrs.find(list) == m_listPtrs.cend())
@@ -1406,7 +1400,7 @@ CompilerValue *LLVMCodeBuilder::addListContents(List *list)
 
 CompilerValue *LLVMCodeBuilder::addListItem(List *list, CompilerValue *index)
 {
-    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, currentLoopScope(), m_loopCondition);
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, m_loopCondition);
     ins->workList = list;
 
     if (m_listPtrs.find(list) == m_listPtrs.cend())
@@ -1425,7 +1419,7 @@ CompilerValue *LLVMCodeBuilder::addListItem(List *list, CompilerValue *index)
 
 CompilerValue *LLVMCodeBuilder::addListItemIndex(List *list, CompilerValue *item)
 {
-    LLVMInstruction ins(LLVMInstruction::Type::GetListItemIndex, currentLoopScope(), m_loopCondition);
+    LLVMInstruction ins(LLVMInstruction::Type::GetListItemIndex, m_loopCondition);
     ins.workList = list;
 
     if (m_listPtrs.find(list) == m_listPtrs.cend())
@@ -1438,7 +1432,7 @@ CompilerValue *LLVMCodeBuilder::addListItemIndex(List *list, CompilerValue *item
 
 CompilerValue *LLVMCodeBuilder::addListContains(List *list, CompilerValue *item)
 {
-    LLVMInstruction ins(LLVMInstruction::Type::ListContainsItem, currentLoopScope(), m_loopCondition);
+    LLVMInstruction ins(LLVMInstruction::Type::ListContainsItem, m_loopCondition);
     ins.workList = list;
 
     if (m_listPtrs.find(list) == m_listPtrs.cend())
@@ -1451,7 +1445,7 @@ CompilerValue *LLVMCodeBuilder::addListContains(List *list, CompilerValue *item)
 
 CompilerValue *LLVMCodeBuilder::addListSize(List *list)
 {
-    LLVMInstruction ins(LLVMInstruction::Type::GetListSize, currentLoopScope(), m_loopCondition);
+    LLVMInstruction ins(LLVMInstruction::Type::GetListSize, m_loopCondition);
     ins.workList = list;
 
     if (m_listPtrs.find(list) == m_listPtrs.cend())
@@ -1475,7 +1469,7 @@ CompilerValue *LLVMCodeBuilder::addProcedureArgument(const std::string &name)
 
     const auto index = it - argNames.begin();
     const Compiler::StaticType type = getProcedureArgType(m_procedurePrototype->argumentTypes()[index]);
-    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ProcedureArg, currentLoopScope(), m_loopCondition);
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ProcedureArg, m_loopCondition);
     auto ret = std::make_shared<LLVMRegister>(type);
     ret->isRawValue = (type != Compiler::StaticType::Unknown);
     ins->functionReturnReg = ret.get();
@@ -1660,24 +1654,19 @@ void LLVMCodeBuilder::createLocalVariableWrite(CompilerLocalVariable *variable,
 
 void LLVMCodeBuilder::createVariableWrite(Variable *variable, CompilerValue *value)
 {
-    LLVMInstruction ins(LLVMInstruction::Type::WriteVariable, currentLoopScope(), m_loopCondition);
+    LLVMInstruction ins(LLVMInstruction::Type::WriteVariable, m_loopCondition);
     ins.workVariable = variable;
     createOp(ins, Compiler::StaticType::Void, Compiler::StaticType::Unknown, { value });
 
     if (m_variablePtrs.find(variable) == m_variablePtrs.cend())
         m_variablePtrs[variable] = LLVMVariablePtr();
 
-    if (m_loopScope >= 0) {
-        auto scope = m_loopScopes[m_loopScope];
-        m_variablePtrs[variable].loopVariableWrites[scope.get()].push_back(m_instructions.last());
-    }
-
     m_variableInstructions.push_back(m_instructions.last());
 }
 
 void LLVMCodeBuilder::createListClear(List *list)
 {
-    LLVMInstruction ins(LLVMInstruction::Type::ClearList, currentLoopScope(), m_loopCondition);
+    LLVMInstruction ins(LLVMInstruction::Type::ClearList, m_loopCondition);
     ins.workList = list;
     createOp(ins, Compiler::StaticType::Void);
 
@@ -1687,7 +1676,7 @@ void LLVMCodeBuilder::createListClear(List *list)
 
 void LLVMCodeBuilder::createListRemove(List *list, CompilerValue *index)
 {
-    LLVMInstruction ins(LLVMInstruction::Type::RemoveListItem, currentLoopScope(), m_loopCondition);
+    LLVMInstruction ins(LLVMInstruction::Type::RemoveListItem, m_loopCondition);
     ins.workList = list;
     createOp(ins, Compiler::StaticType::Void, Compiler::StaticType::Number, { index });
 
@@ -1697,71 +1686,56 @@ void LLVMCodeBuilder::createListRemove(List *list, CompilerValue *index)
 
 void LLVMCodeBuilder::createListAppend(List *list, CompilerValue *item)
 {
-    LLVMInstruction ins(LLVMInstruction::Type::AppendToList, currentLoopScope(), m_loopCondition);
+    LLVMInstruction ins(LLVMInstruction::Type::AppendToList, m_loopCondition);
     ins.workList = list;
     createOp(ins, Compiler::StaticType::Void, Compiler::StaticType::Unknown, { item });
 
     if (m_listPtrs.find(list) == m_listPtrs.cend())
         m_listPtrs[list] = LLVMListPtr();
 
-    if (m_loopScope >= 0) {
-        auto scope = m_loopScopes[m_loopScope];
-        m_listPtrs[list].loopListWrites[scope.get()].push_back(m_instructions.last());
-    }
-
     m_listInstructions.push_back(m_instructions.last());
 }
 
 void LLVMCodeBuilder::createListInsert(List *list, CompilerValue *index, CompilerValue *item)
 {
-    LLVMInstruction ins(LLVMInstruction::Type::InsertToList, currentLoopScope(), m_loopCondition);
+    LLVMInstruction ins(LLVMInstruction::Type::InsertToList, m_loopCondition);
     ins.workList = list;
     createOp(ins, Compiler::StaticType::Void, { Compiler::StaticType::Number, Compiler::StaticType::Unknown }, { index, item });
 
     if (m_listPtrs.find(list) == m_listPtrs.cend())
         m_listPtrs[list] = LLVMListPtr();
 
-    if (m_loopScope >= 0) {
-        auto scope = m_loopScopes[m_loopScope];
-        m_listPtrs[list].loopListWrites[scope.get()].push_back(m_instructions.last());
-    }
-
     m_listInstructions.push_back(m_instructions.last());
 }
 
 void LLVMCodeBuilder::createListReplace(List *list, CompilerValue *index, CompilerValue *item)
 {
-    LLVMInstruction ins(LLVMInstruction::Type::ListReplace, currentLoopScope(), m_loopCondition);
+    LLVMInstruction ins(LLVMInstruction::Type::ListReplace, m_loopCondition);
     ins.workList = list;
     createOp(ins, Compiler::StaticType::Void, { Compiler::StaticType::Number, Compiler::StaticType::Unknown }, { index, item });
 
     if (m_listPtrs.find(list) == m_listPtrs.cend())
         m_listPtrs[list] = LLVMListPtr();
 
-    if (m_loopScope >= 0) {
-        auto scope = m_loopScopes[m_loopScope];
-        m_listPtrs[list].loopListWrites[scope.get()].push_back(m_instructions.last());
-    }
-
     m_listInstructions.push_back(m_instructions.last());
 }
 
 void LLVMCodeBuilder::beginIfStatement(CompilerValue *cond)
 {
-    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, currentLoopScope(), m_loopCondition);
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, m_loopCondition);
     ins->args.push_back({ Compiler::StaticType::Bool, dynamic_cast<LLVMRegister *>(cond) });
     m_instructions.addInstruction(ins);
 }
 
 void LLVMCodeBuilder::beginElseBranch()
 {
-    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, currentLoopScope(), m_loopCondition);
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, m_loopCondition);
     m_instructions.addInstruction(ins);
 }
 
 void LLVMCodeBuilder::endIf()
 {
-    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, currentLoopScope(), m_loopCondition);
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, m_loopCondition);
     m_instructions.addInstruction(ins);
 }
 
@@ -1769,10 +1743,9 @@ void LLVMCodeBuilder::beginRepeatLoop(CompilerValue *count)
 {
     assert(!m_loopCondition);
 
-    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, currentLoopScope(), m_loopCondition);
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, m_loopCondition);
     ins->args.push_back({ Compiler::StaticType::Number, dynamic_cast<LLVMRegister *>(count) });
     m_instructions.addInstruction(ins);
-    pushLoopScope(false);
 }
 
 void LLVMCodeBuilder::beginWhileLoop(CompilerValue *cond)
@@ -1780,10 +1753,9 @@ void LLVMCodeBuilder::beginWhileLoop(CompilerValue *cond)
     assert(m_loopCondition);
     m_loopCondition = false;
 
-    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginWhileLoop, currentLoopScope(), m_loopCondition);
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginWhileLoop, m_loopCondition);
     ins->args.push_back({ Compiler::StaticType::Bool, dynamic_cast<LLVMRegister *>(cond) });
     m_instructions.addInstruction(ins);
-    pushLoopScope(false);
 }
 
 void LLVMCodeBuilder::beginRepeatUntilLoop(CompilerValue *cond)
@@ -1791,17 +1763,16 @@ void LLVMCodeBuilder::beginRepeatUntilLoop(CompilerValue *cond)
     assert(m_loopCondition);
     m_loopCondition = false;
 
-    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, currentLoopScope(), m_loopCondition);
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, m_loopCondition);
     ins->args.push_back({ Compiler::StaticType::Bool, dynamic_cast<LLVMRegister *>(cond) });
     m_instructions.addInstruction(ins);
-    pushLoopScope(false);
 }
 
 void LLVMCodeBuilder::beginLoopCondition()
 {
     assert(!m_loopCondition);
 
-    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginLoopCondition, currentLoopScope(), m_loopCondition);
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginLoopCondition, m_loopCondition);
     m_instructions.addInstruction(ins);
     m_loopCondition = true;
 }
@@ -1809,27 +1780,23 @@ void LLVMCodeBuilder::beginLoopCondition()
 void LLVMCodeBuilder::endLoop()
 {
     if (!m_warp) {
-        auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Yield, currentLoopScope(), m_loopCondition);
+        auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Yield, m_loopCondition);
         m_instructions.addInstruction(ins);
     }
 
-    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, currentLoopScope(), m_loopCondition);
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, m_loopCondition);
     m_instructions.addInstruction(ins);
-    popLoopScope();
 }
 
 void LLVMCodeBuilder::yield()
 {
-    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Yield, currentLoopScope(), m_loopCondition);
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Yield, m_loopCondition);
     m_instructions.addInstruction(ins);
-
-    if (m_loopScope >= 0)
-        m_loopScopes[m_loopScope]->containsYield = true;
 }
 
 void LLVMCodeBuilder::createStop()
 {
-    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Stop, currentLoopScope(), m_loopCondition);
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Stop, m_loopCondition);
     m_instructions.addInstruction(ins);
 }
 
@@ -1843,7 +1810,7 @@ void LLVMCodeBuilder::createProcedureCall(BlockPrototype *prototype, const Compi
     for (BlockPrototype::ArgType type : procedureArgs)
         types.push_back(getProcedureArgType(type));
 
-    LLVMInstruction ins(LLVMInstruction::Type::CallProcedure, currentLoopScope(), m_loopCondition);
+    LLVMInstruction ins(LLVMInstruction::Type::CallProcedure, m_loopCondition);
     ins.procedurePrototype = prototype;
     createOp(ins, Compiler::StaticType::Void, types, args);
 }
@@ -1926,36 +1893,6 @@ void LLVMCodeBuilder::popScopeLevel()
     m_stringHeap.pop_back();
 }
 
-void LLVMCodeBuilder::pushLoopScope(bool buildPhase)
-{
-    if (buildPhase)
-        m_loopScope = m_loopScopeCounter++;
-    else {
-        auto scope = std::make_shared<LLVMLoopScope>();
-        m_loopScopes.push_back(scope);
-
-        if (m_loopScope >= 0) {
-            auto currentScope = m_loopScopes[m_loopScope];
-            currentScope->childScopes.push_back(scope.get());
-            scope->parentScope = currentScope.get();
-        }
-
-        m_loopScope = m_loopScopes.size() - 1;
-    }
-
-    m_loopScopeTree.push_back(m_loopScope);
-}
-
-void LLVMCodeBuilder::popLoopScope()
-{
-    m_loopScopeTree.pop_back();
-
-    if (m_loopScopeTree.empty()) {
-        m_loopScope = -1;
-    } else
-        m_loopScope = m_loopScopeTree.back();
-}
-
 std::string LLVMCodeBuilder::getMainFunctionName(BlockPrototype *procedurePrototype)
 {
     std::string name;
@@ -2392,12 +2329,12 @@ void LLVMCodeBuilder::reloadVariables(llvm::Value *targetVariables)
 
 LLVMRegister *LLVMCodeBuilder::createOp(LLVMInstruction::Type type, Compiler::StaticType retType, Compiler::StaticType argType, const Compiler::Args &args)
 {
-    return createOp({ type, currentLoopScope(), m_loopCondition }, retType, argType, args);
+    return createOp({ type, m_loopCondition }, retType, argType, args);
 }
 
 LLVMRegister *LLVMCodeBuilder::createOp(LLVMInstruction::Type type, Compiler::StaticType retType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args)
 {
-    return createOp({ type, currentLoopScope(), m_loopCondition }, retType, argTypes, args);
+    return createOp({ type, m_loopCondition }, retType, argTypes, args);
 }
 
 LLVMRegister *LLVMCodeBuilder::createOp(const LLVMInstruction &ins, Compiler::StaticType retType, Compiler::StaticType argType, const Compiler::Args &args)
@@ -2429,11 +2366,6 @@ LLVMRegister *LLVMCodeBuilder::createOp(const LLVMInstruction &ins, Compiler::St
     return nullptr;
 }
 
-LLVMLoopScope *LLVMCodeBuilder::currentLoopScope() const
-{
-    return m_loopScope >= 0 ? m_loopScopes[m_loopScope].get() : nullptr;
-}
-
 void LLVMCodeBuilder::createValueStore(LLVMRegister *reg, llvm::Value *targetPtr, Compiler::StaticType sourceType, Compiler::StaticType targetType)
 {
     llvm::Value *converted = nullptr;
diff --git a/src/engine/internal/llvm/llvmcodebuilder.h b/src/engine/internal/llvm/llvmcodebuilder.h
index c89d9db3..6a831929 100644
--- a/src/engine/internal/llvm/llvmcodebuilder.h
+++ b/src/engine/internal/llvm/llvmcodebuilder.h
@@ -23,7 +23,6 @@ namespace libscratchcpp
 
 class LLVMCompilerContext;
 class LLVMConstantRegister;
-class LLVMLoopScope;
 
 class LLVMCodeBuilder : public ICodeBuilder
 {
@@ -127,8 +126,6 @@ class LLVMCodeBuilder : public ICodeBuilder
         void createListMap();
         void pushScopeLevel();
         void popScopeLevel();
-        void pushLoopScope(bool buildPhase);
-        void popLoopScope();
 
         std::string getMainFunctionName(BlockPrototype *procedurePrototype);
         llvm::FunctionType *getMainFunctionType(BlockPrototype *procedurePrototype);
@@ -159,7 +156,6 @@ class LLVMCodeBuilder : public ICodeBuilder
         LLVMRegister *createOp(LLVMInstruction::Type type, Compiler::StaticType retType, const Compiler::ArgTypes &argTypes = {}, const Compiler::Args &args = {});
         LLVMRegister *createOp(const LLVMInstruction &ins, Compiler::StaticType retType, Compiler::StaticType argType, const Compiler::Args &args);
         LLVMRegister *createOp(const LLVMInstruction &ins, Compiler::StaticType retType, const Compiler::ArgTypes &argTypes = {}, const Compiler::Args &args = {});
-        LLVMLoopScope *currentLoopScope() const;
 
         void createValueStore(LLVMRegister *reg, llvm::Value *targetPtr, Compiler::StaticType sourceType, Compiler::StaticType targetType);
         void createReusedValueStore(LLVMRegister *reg, llvm::Value *targetPtr, Compiler::StaticType sourceType, Compiler::StaticType targetType);
@@ -203,16 +199,10 @@ class LLVMCodeBuilder : public ICodeBuilder
         int m_defaultArgCount = 0;
         Compiler::CodeType m_codeType = Compiler::CodeType::Script;
 
-        long m_loopScope = -1; // index
-        std::vector<std::shared_ptr<LLVMLoopScope>> m_loopScopes;
-        long m_loopScopeCounter = 0; // replacement for m_loopScopes size in build phase
-        std::vector<long> m_loopScopeTree;
         bool m_loopCondition = false; // whether we're currently compiling a loop condition
         std::vector<LLVMInstruction *> m_variableInstructions;
         std::vector<LLVMInstruction *> m_listInstructions;
         std::vector<std::vector<llvm::Value *>> m_stringHeap; // scopes
-
-        std::shared_ptr<ExecutableCode> m_output;
 };
 
 } // namespace libscratchcpp
diff --git a/src/engine/internal/llvm/llvminstruction.h b/src/engine/internal/llvm/llvminstruction.h
index 091539bb..e4fa059a 100644
--- a/src/engine/internal/llvm/llvminstruction.h
+++ b/src/engine/internal/llvm/llvminstruction.h
@@ -10,7 +10,6 @@ namespace libscratchcpp
 {
 
 class BlockPrototype;
-class LLVMLoopScope;
 
 struct LLVMInstruction
 {
@@ -81,9 +80,8 @@ struct LLVMInstruction
             ProcedureArg
         };
 
-        LLVMInstruction(Type type, LLVMLoopScope *loopScope, bool loopCondition) :
+        LLVMInstruction(Type type, bool loopCondition) :
             type(type),
-            loopScope(loopScope),
             loopCondition(loopCondition)
         {
         }
@@ -98,7 +96,6 @@ struct LLVMInstruction
         List *workList = nullptr;         // for lists
         BlockPrototype *procedurePrototype = nullptr;
         size_t procedureArgIndex = 0;
-        LLVMLoopScope *loopScope = nullptr;
         bool loopCondition = false; // whether the instruction is part of a loop condition
 
         // Linked list
diff --git a/src/engine/internal/llvm/llvmlistptr.h b/src/engine/internal/llvm/llvmlistptr.h
index 7b13bc39..1dd42c60 100644
--- a/src/engine/internal/llvm/llvmlistptr.h
+++ b/src/engine/internal/llvm/llvmlistptr.h
@@ -3,7 +3,6 @@
 #pragma once
 
 #include <scratchcpp/compiler.h>
-#include <unordered_map>
 
 namespace llvm
 {
@@ -15,7 +14,6 @@ class Value;
 namespace libscratchcpp
 {
 
-class LLVMLoopScope;
 class LLVMInstruction;
 
 struct LLVMListPtr
@@ -24,9 +22,6 @@ struct LLVMListPtr
         llvm::Value *dataPtr = nullptr;
         llvm::Value *sizePtr = nullptr;
         llvm::Value *allocatedSizePtr = nullptr;
-
-        // Used in build phase to check the type safety of lists in loops
-        std::unordered_map<LLVMLoopScope *, std::vector<LLVMInstruction *>> loopListWrites; // loop scope, write instructions
 };
 
 } // namespace libscratchcpp
diff --git a/src/engine/internal/llvm/llvmloopscope.h b/src/engine/internal/llvm/llvmloopscope.h
deleted file mode 100644
index 5e34647c..00000000
--- a/src/engine/internal/llvm/llvmloopscope.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-
-#pragma once
-
-#include <vector>
-#include <memory>
-
-namespace libscratchcpp
-{
-
-struct LLVMLoopScope
-{
-        bool containsYield = false;
-        LLVMLoopScope *parentScope = nullptr;
-        std::vector<LLVMLoopScope *> childScopes;
-};
-
-} // namespace libscratchcpp
diff --git a/src/engine/internal/llvm/llvmvariableptr.h b/src/engine/internal/llvm/llvmvariableptr.h
index 1627da6f..2e5b3d01 100644
--- a/src/engine/internal/llvm/llvmvariableptr.h
+++ b/src/engine/internal/llvm/llvmvariableptr.h
@@ -3,7 +3,6 @@
 #pragma once
 
 #include <scratchcpp/compiler.h>
-#include <unordered_map>
 
 namespace llvm
 {
@@ -15,7 +14,6 @@ class Value;
 namespace libscratchcpp
 {
 
-class LLVMLoopScope;
 class LLVMInstruction;
 
 struct LLVMVariablePtr
@@ -24,9 +22,6 @@ struct LLVMVariablePtr
         llvm::Value *heapPtr = nullptr;
         bool onStack = false;
         bool changed = false;
-
-        // Used in build phase to check the type safety of variables in loops
-        std::unordered_map<LLVMLoopScope *, std::vector<LLVMInstruction *>> loopVariableWrites; // loop scope, write instructions
 };
 
 } // namespace libscratchcpp
diff --git a/test/llvm/llvminstructionlist_test.cpp b/test/llvm/llvminstructionlist_test.cpp
index 7cc12584..02535da2 100644
--- a/test/llvm/llvminstructionlist_test.cpp
+++ b/test/llvm/llvminstructionlist_test.cpp
@@ -32,14 +32,14 @@ TEST(LLVMInstructionListTest, EmptyList_ContainsNull)
 TEST(LLVMInstructionListTest, EmptyList_ContainsFunc)
 {
     LLVMInstructionList list;
-    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     ASSERT_FALSE(list.containsInstruction([](const LLVMInstruction *) { return true; }));
 }
 
 TEST(LLVMInstructionListTest, EmptyList_Contains)
 {
     LLVMInstructionList list;
-    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     ASSERT_FALSE(list.containsInstruction(ins.get()));
 }
 
@@ -47,7 +47,7 @@ TEST(LLVMInstructionListTest, SingleInstructionList_ContainsExistent)
 {
     LLVMInstructionList list;
 
-    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins1);
 
     ASSERT_TRUE(list.containsInstruction(ins1.get()));
@@ -57,10 +57,10 @@ TEST(LLVMInstructionListTest, SingleInstructionList_ContainsNonExistent)
 {
     LLVMInstructionList list;
 
-    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins1);
 
-    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     ASSERT_FALSE(list.containsInstruction(ins.get()));
 }
 
@@ -68,7 +68,7 @@ TEST(LLVMInstructionListTest, SingleInstructionList_ContainsNull)
 {
     LLVMInstructionList list;
 
-    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins1);
 
     ASSERT_FALSE(list.containsInstruction(nullptr));
@@ -78,7 +78,7 @@ TEST(LLVMInstructionListTest, SingleInstructionList_ContainsFuncTrue)
 {
     LLVMInstructionList list;
 
-    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins1);
 
     ASSERT_TRUE(list.containsInstruction([](const LLVMInstruction *) { return true; }));
@@ -88,10 +88,10 @@ TEST(LLVMInstructionListTest, SingleInstructionList_ContainsFuncFalse)
 {
     LLVMInstructionList list;
 
-    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins1);
 
-    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     ASSERT_FALSE(list.containsInstruction([](const LLVMInstruction *) { return false; }));
 }
 
@@ -99,13 +99,13 @@ TEST(LLVMInstructionListTest, MultipleInstructionList_ContainsExistent)
 {
     LLVMInstructionList list;
 
-    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins1);
 
-    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins2);
 
-    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins3);
 
     ASSERT_TRUE(list.containsInstruction(ins2.get()));
@@ -115,16 +115,16 @@ TEST(LLVMInstructionListTest, MultipleInstructionList_ContainsNonExistent)
 {
     LLVMInstructionList list;
 
-    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins1);
 
-    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins2);
 
-    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins3);
 
-    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     ASSERT_FALSE(list.containsInstruction(ins.get()));
 }
 
@@ -132,13 +132,13 @@ TEST(LLVMInstructionListTest, MultipleInstructionList_ContainsNull)
 {
     LLVMInstructionList list;
 
-    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins1);
 
-    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins2);
 
-    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins3);
 
     ASSERT_FALSE(list.containsInstruction(nullptr));
@@ -148,13 +148,13 @@ TEST(LLVMInstructionListTest, MultipleInstructionList_ContainsExistentFunc)
 {
     LLVMInstructionList list;
 
-    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins1);
 
-    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Stop, nullptr, false);
+    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Stop, false);
     list.addInstruction(ins2);
 
-    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins3);
 
     ASSERT_TRUE(list.containsInstruction([](const LLVMInstruction *ins) { return ins->type == LLVMInstruction::Type::Stop; }));
@@ -164,13 +164,13 @@ TEST(LLVMInstructionListTest, MultipleInstructionList_ContainsNonExistentFunc)
 {
     LLVMInstructionList list;
 
-    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins1);
 
-    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins2);
 
-    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins3);
 
     ASSERT_FALSE(list.containsInstruction([](const LLVMInstruction *ins) { return ins->type == LLVMInstruction::Type::Stop; }));
@@ -179,7 +179,7 @@ TEST(LLVMInstructionListTest, MultipleInstructionList_ContainsNonExistentFunc)
 TEST(LLVMInstructionListTest, AddSingleInstruction_First)
 {
     LLVMInstructionList list;
-    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins);
 
     ASSERT_EQ(list.first(), ins.get());
@@ -188,7 +188,7 @@ TEST(LLVMInstructionListTest, AddSingleInstruction_First)
 TEST(LLVMInstructionListTest, AddSingleInstruction_Last)
 {
     LLVMInstructionList list;
-    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins);
 
     ASSERT_EQ(list.last(), ins.get());
@@ -197,7 +197,7 @@ TEST(LLVMInstructionListTest, AddSingleInstruction_Last)
 TEST(LLVMInstructionListTest, AddSingleInstruction_Empty)
 {
     LLVMInstructionList list;
-    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins);
 
     ASSERT_FALSE(list.empty());
@@ -206,7 +206,7 @@ TEST(LLVMInstructionListTest, AddSingleInstruction_Empty)
 TEST(LLVMInstructionListTest, AddSingleInstruction_Previous)
 {
     LLVMInstructionList list;
-    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins);
 
     ASSERT_EQ(ins->previous, nullptr);
@@ -215,7 +215,7 @@ TEST(LLVMInstructionListTest, AddSingleInstruction_Previous)
 TEST(LLVMInstructionListTest, AddSingleInstruction_Next)
 {
     LLVMInstructionList list;
-    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins);
 
     ASSERT_EQ(ins->next, nullptr);
@@ -225,13 +225,13 @@ TEST(LLVMInstructionListTest, AddMultipleInstructions_First)
 {
     LLVMInstructionList list;
 
-    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins1);
 
-    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins2);
 
-    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins3);
 
     ASSERT_EQ(list.first(), ins1.get());
@@ -241,13 +241,13 @@ TEST(LLVMInstructionListTest, AddMultipleInstructions_Last)
 {
     LLVMInstructionList list;
 
-    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins1);
 
-    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins2);
 
-    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins3);
 
     ASSERT_EQ(list.last(), ins3.get());
@@ -257,13 +257,13 @@ TEST(LLVMInstructionListTest, AddMultipleInstructions_Empty)
 {
     LLVMInstructionList list;
 
-    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins1);
 
-    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins2);
 
-    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins3);
 
     ASSERT_FALSE(list.empty());
@@ -273,13 +273,13 @@ TEST(LLVMInstructionListTest, AddMultipleInstructions_PreviousOfFirst)
 {
     LLVMInstructionList list;
 
-    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins1);
 
-    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins2);
 
-    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins3);
 
     ASSERT_EQ(ins1->previous, nullptr);
@@ -289,13 +289,13 @@ TEST(LLVMInstructionListTest, AddMultipleInstructions_NextOfFirst)
 {
     LLVMInstructionList list;
 
-    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins1);
 
-    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins2);
 
-    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins3);
 
     ASSERT_EQ(ins1->next, ins2.get());
@@ -305,13 +305,13 @@ TEST(LLVMInstructionListTest, AddMultipleInstructions_PreviousOfMiddle)
 {
     LLVMInstructionList list;
 
-    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins1);
 
-    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins2);
 
-    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins3);
 
     ASSERT_EQ(ins2->previous, ins1.get());
@@ -321,13 +321,13 @@ TEST(LLVMInstructionListTest, AddMultipleInstructions_NextOfMiddle)
 {
     LLVMInstructionList list;
 
-    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins1);
 
-    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins2);
 
-    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins3);
 
     ASSERT_EQ(ins2->next, ins3.get());
@@ -337,13 +337,13 @@ TEST(LLVMInstructionListTest, AddMultipleInstructions_PreviousOfLast)
 {
     LLVMInstructionList list;
 
-    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins1);
 
-    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins2);
 
-    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins3);
 
     ASSERT_EQ(ins3->previous, ins2.get());
@@ -353,13 +353,13 @@ TEST(LLVMInstructionListTest, AddMultipleInstructions_NextOfLast)
 {
     LLVMInstructionList list;
 
-    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins1);
 
-    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins2);
 
-    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto ins3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(ins3);
 
     ASSERT_EQ(ins3->next, nullptr);
diff --git a/test/llvm/type_analyzer/listtype_test.cpp b/test/llvm/type_analyzer/listtype_test.cpp
index 54e6bc98..a1183dc9 100644
--- a/test/llvm/type_analyzer/listtype_test.cpp
+++ b/test/llvm/type_analyzer/listtype_test.cpp
@@ -18,7 +18,7 @@ TEST(LLVMTypeAnalyzer_ListType, NullList)
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList instructionList;
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(nullptr, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
@@ -37,7 +37,7 @@ TEST(LLVMTypeAnalyzer_ListType, NoWriteOperationsKnownType_NonEmpty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
@@ -49,7 +49,7 @@ TEST(LLVMTypeAnalyzer_ListType, NoWriteOperationsKnownType_Empty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Number);
@@ -61,7 +61,7 @@ TEST(LLVMTypeAnalyzer_ListType, NoWriteOperationsUnknownType_NonEmpty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Unknown, false), Compiler::StaticType::Unknown);
@@ -73,7 +73,7 @@ TEST(LLVMTypeAnalyzer_ListType, NoWriteOperationsUnknownType_Empty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Unknown, true), Compiler::StaticType::Unknown);
@@ -85,7 +85,7 @@ TEST(LLVMTypeAnalyzer_ListType, QueryPointIsWrite)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 1.25);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
@@ -100,19 +100,19 @@ TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteSameTypeNumber_Before_NonEmpty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 1.25);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
@@ -124,19 +124,19 @@ TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteSameTypeNumber_Before_Empty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 1.25);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Number);
@@ -148,19 +148,19 @@ TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteStringOptimization_Empty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "1.25");
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // String "1.25" gets optimized to Number type
@@ -174,27 +174,27 @@ TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteMultipleLists)
     List list1("", "");
     List list2("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // Append to list1
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 6);
     appendList1->workList = &list1;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Append to list2
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     appendList2->workList = &list2;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listType(&list1, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
@@ -206,19 +206,19 @@ TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteFromUnknownType_Before_NonEmpty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMRegister value(Compiler::StaticType::Unknown);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
@@ -230,19 +230,19 @@ TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteFromUnknownType_Before_Empty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMRegister value(Compiler::StaticType::Unknown);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown);
@@ -254,19 +254,19 @@ TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteToUnknownType_Before_Empty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 5);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // The type is known because a number is appended before the point
@@ -279,19 +279,19 @@ TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteToUnknownType_Before_NonEmpty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 5);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Unknown, false), Compiler::StaticType::Unknown);
@@ -303,19 +303,19 @@ TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteDifferentTypeNumberToString_Befo
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String);
@@ -327,19 +327,19 @@ TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteDifferentTypeNumberToString_Befo
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
@@ -351,19 +351,19 @@ TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteDifferentTypeBoolToNumber_Before
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 1);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Bool, true), Compiler::StaticType::Number);
@@ -375,25 +375,25 @@ TEST(LLVMTypeAnalyzer_ListType, Loop_SingleWriteDifferentType_BeforeAndAfter)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "test");
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Bool, true);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
@@ -405,19 +405,19 @@ TEST(LLVMTypeAnalyzer_ListType, IfStatement_SingleWriteDifferentType_Before)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
@@ -429,19 +429,19 @@ TEST(LLVMTypeAnalyzer_ListType, IfStatement_SingleWriteDifferentType_After_IfBra
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(start);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(end);
 
     // Since this isn't a loop, the write after the point doesn't affect the type
@@ -454,22 +454,22 @@ TEST(LLVMTypeAnalyzer_ListType, IfStatement_SingleWriteDifferentType_After_ElseB
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(start);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(end);
 
     // Since this isn't a loop, the write after the point doesn't affect the type
@@ -482,19 +482,19 @@ TEST(LLVMTypeAnalyzer_ListType, WriteSameTypeInLoop_NonEmpty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 1.25);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
@@ -506,19 +506,19 @@ TEST(LLVMTypeAnalyzer_ListType, WriteSameTypeInLoop_Empty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 1.25);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Number);
@@ -530,19 +530,19 @@ TEST(LLVMTypeAnalyzer_ListType, WriteDifferentTypeInLoop_NonEmpty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Type is not known because the loop might not run at all
@@ -555,19 +555,19 @@ TEST(LLVMTypeAnalyzer_ListType, WriteDifferentTypeInLoop_Empty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Type is String because empty list can establish new type
@@ -580,25 +580,25 @@ TEST(LLVMTypeAnalyzer_ListType, ChangeTypeBeforeLoop_NonEmpty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 1.25);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::Unknown);
@@ -610,25 +610,25 @@ TEST(LLVMTypeAnalyzer_ListType, OverrideUnknownTypeBeforeLoop_Empty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 1.25);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Unknown, true), Compiler::StaticType::Number);
@@ -640,19 +640,19 @@ TEST(LLVMTypeAnalyzer_ListType, WriteSameTypeInIfStatement_NonEmpty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 1.25);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
@@ -664,19 +664,19 @@ TEST(LLVMTypeAnalyzer_ListType, WriteDifferentTypeInIfStatement_NonEmpty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 5.8);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Type is not known because the if statement might not run at all
@@ -689,34 +689,34 @@ TEST(LLVMTypeAnalyzer_ListType, OverrideDifferentTypeBeforeIfElseStatement_Empty
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 1.25);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(start);
 
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
-    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value3(Compiler::StaticType::Number, 2.5);
     appendList3->workList = &list;
     appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     instructionList.addInstruction(appendList3);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, true), Compiler::StaticType::Number);
@@ -728,34 +728,34 @@ TEST(LLVMTypeAnalyzer_ListType, OverrideUnknownTypeBeforeIfElseStatement_Empty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 1.25);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(start);
 
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
-    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value3(Compiler::StaticType::Number, 2.5);
     appendList3->workList = &list;
     appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     instructionList.addInstruction(appendList3);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Unknown, true), Compiler::StaticType::Number);
@@ -768,20 +768,20 @@ TEST(LLVMTypeAnalyzer_ListType, MultipleWritesSameTypeNumber_NonEmpty)
     List list("", "");
 
     // First write: string "abc" (incompatible with Number)
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "abc");
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Second write: number 5.25 (incompatible with previous String)
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 5.25);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should return Unknown type because of type conflict
@@ -795,20 +795,20 @@ TEST(LLVMTypeAnalyzer_ListType, MultipleWritesSameTypeString_Empty)
     List list("", "");
 
     // First write: number 42 (establishes Number type for empty list)
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Second write: string "hello" (incompatible with Number)
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "hello");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should return Unknown type because of type conflict
@@ -822,20 +822,20 @@ TEST(LLVMTypeAnalyzer_ListType, MultipleWritesSameTypeUnknown_Empty)
     List list("", "");
 
     // First write: unknown type
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMRegister value1(Compiler::StaticType::Unknown);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Second write: string "hello"
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "hello");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should return Unknown type because first write is unknown
@@ -849,20 +849,20 @@ TEST(LLVMTypeAnalyzer_ListType, MultipleWritesWithStringOptimization_Empty)
     List list("", "");
 
     // First write: number 5
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Second write: string "3.14" (optimized to Number)
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "3.14");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should return Number type because the string gets optimized to number
@@ -876,20 +876,20 @@ TEST(LLVMTypeAnalyzer_ListType, MultipleWritesNumberToString_NonEmpty)
     List list("", "");
 
     // First write: number 42 (compatible with Number)
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Second write: string "hello" (incompatible with Number)
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "hello");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should return Unknown type because of type conflict
@@ -903,20 +903,20 @@ TEST(LLVMTypeAnalyzer_ListType, MultipleWritesNumberToString_Empty)
     List list("", "");
 
     // First write: number 42 (establishes Number type for empty list)
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Second write: string "hello" (incompatible with Number)
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "hello");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should return Unknown type because of type conflict
@@ -929,13 +929,13 @@ TEST(LLVMTypeAnalyzer_ListType, MultipleWritesBoolToNumber_NonEmpty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 42.5);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should return Unknown type because Number conflicts with Bool
@@ -948,13 +948,13 @@ TEST(LLVMTypeAnalyzer_ListType, MultipleWritesBoolToNumber_Empty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 42.5);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should return Number type because empty list establishes new type
@@ -967,13 +967,13 @@ TEST(LLVMTypeAnalyzer_ListType, MultipleWritesBoolToString_NonEmpty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "hello");
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should return Unknown type because String conflicts with Bool
@@ -986,13 +986,13 @@ TEST(LLVMTypeAnalyzer_ListType, MultipleWritesBoolToString_Empty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "hello");
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should return String type because empty list establishes new type
@@ -1005,13 +1005,13 @@ TEST(LLVMTypeAnalyzer_ListType, MultipleWritesBoolToStringNumberOptimization_Non
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "3.14");
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // String "3.14" gets optimized to Number, which conflicts with Bool
@@ -1024,13 +1024,13 @@ TEST(LLVMTypeAnalyzer_ListType, MultipleWritesBoolToStringNumberOptimization_Emp
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "3.14");
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // String "3.14" gets optimized to Number type
@@ -1043,30 +1043,30 @@ TEST(LLVMTypeAnalyzer_ListType, TypeChangeInIfBranch_NonEmpty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // First write - changes type
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "test");
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
     // Second write - does not change type
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 42);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Returns unknown type because both branches might run
@@ -1079,30 +1079,30 @@ TEST(LLVMTypeAnalyzer_ListType, TypeChangeInIfBranch_Empty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // First write - changes type
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "test");
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
     // Second write - different type
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 42);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Returns unknown type because different types in branches
@@ -1115,30 +1115,30 @@ TEST(LLVMTypeAnalyzer_ListType, TypeChangeInElseBranch_NonEmpty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // First write - does not change type
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
     // Second write - changes type
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Returns unknown type because both branches might run
@@ -1151,30 +1151,30 @@ TEST(LLVMTypeAnalyzer_ListType, TypeChangeInElseBranch_Empty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // First write - establishes Number type
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
     // Second write - establishes String type
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Returns unknown type because different types in branches
@@ -1187,30 +1187,30 @@ TEST(LLVMTypeAnalyzer_ListType, IfElseWithEqualTypes_SameType_NonEmpty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // First write - does not change type
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
     // Second write - does not change type
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
@@ -1222,30 +1222,30 @@ TEST(LLVMTypeAnalyzer_ListType, IfElseWithEqualTypes_SameType_Empty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // First write - establishes Number type
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
     // Second write - establishes same Number type
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Number);
@@ -1257,30 +1257,30 @@ TEST(LLVMTypeAnalyzer_ListType, IfElseWithEqualTypes_DifferentTypes_NonEmpty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // First write - changes type to string
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "Lorem");
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
     // Second write - changes type to string
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "ipsum");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
@@ -1292,30 +1292,30 @@ TEST(LLVMTypeAnalyzer_ListType, IfElseWithEqualTypes_DifferentTypes_Empty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // First write - establishes String type
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "Lorem");
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
     // Second write - establishes same String type
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "ipsum");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String);
@@ -1327,33 +1327,33 @@ TEST(LLVMTypeAnalyzer_ListType, IfStatementAfterLoop_SameTypes_NonEmpty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(loopStart);
 
     // First write - does not change type
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
-    auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(loopEnd);
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // Second write - does not change type
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 2);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
@@ -1365,33 +1365,33 @@ TEST(LLVMTypeAnalyzer_ListType, IfStatementAfterLoop_SameTypes_Empty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(loopStart);
 
     // First write - establishes type for empty list
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
-    auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(loopEnd);
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // Second write - same type
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 2);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Number);
@@ -1403,33 +1403,33 @@ TEST(LLVMTypeAnalyzer_ListType, IfStatementAfterLoop_DifferentTypes_NonEmpty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(loopStart);
 
     // First write - does not change type
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
-    auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(loopEnd);
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // Second write - changes type
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
@@ -1441,33 +1441,33 @@ TEST(LLVMTypeAnalyzer_ListType, IfStatementAfterLoop_DifferentTypes_Empty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(loopStart);
 
     // First write - establishes Number type for empty list
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
-    auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(loopEnd);
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // Second write - adds string
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown);
@@ -1479,46 +1479,46 @@ TEST(LLVMTypeAnalyzer_ListType, TwoIfStatements_DifferentTypes_NonEmpty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // First write - does not change type
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
     // Second write - does not change type
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 4);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
-    ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
-    elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
     // Third write - adds string (in else branch)
-    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value3(Compiler::StaticType::String, "test");
     appendList3->workList = &list;
     appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     instructionList.addInstruction(appendList3);
 
-    ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
@@ -1530,46 +1530,46 @@ TEST(LLVMTypeAnalyzer_ListType, TwoIfStatements_DifferentTypes_Empty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // First write - establishes Number type
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
     // Second write - same Number type
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 4);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
-    ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
-    elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
     // Third write - adds String (in else branch)
-    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value3(Compiler::StaticType::String, "test");
     appendList3->workList = &list;
     appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     instructionList.addInstruction(appendList3);
 
-    ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown);
@@ -1582,36 +1582,36 @@ TEST(LLVMTypeAnalyzer_ListType, NestedLoopWithTypeChange_Before_NonEmpty)
     List list("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(outerLoop);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // List write inside outer loop
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Inner loop begin
-    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(innerLoop);
 
     // List write inside inner loop
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
     // Inner loop end
-    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(innerEnd);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(outerEnd);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
@@ -1624,36 +1624,36 @@ TEST(LLVMTypeAnalyzer_ListType, NestedLoopWithTypeChange_Before_Empty)
     List list("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(outerLoop);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // List write inside outer loop
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Inner loop begin
-    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(innerLoop);
 
     // List write inside inner loop
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
     // Inner loop end
-    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(innerEnd);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(outerEnd);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown);
@@ -1666,36 +1666,36 @@ TEST(LLVMTypeAnalyzer_ListType, NestedLoopWithTypeChange_BeforeInner_NonEmpty)
     List list("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(outerLoop);
 
     // List write inside outer loop
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Inner loop begin
-    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(innerLoop);
 
     // List write inside inner loop
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
     // Inner loop end
-    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(innerEnd);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(outerEnd);
 
     // Returns Unknown because a string might be added
@@ -1709,36 +1709,36 @@ TEST(LLVMTypeAnalyzer_ListType, NestedLoopWithTypeChange_BeforeInner_Empty)
     List list("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(outerLoop);
 
     // List write inside outer loop
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Inner loop begin
-    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(innerLoop);
 
     // List write inside inner loop
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
     // Inner loop end
-    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(innerEnd);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(outerEnd);
 
     // Returns Unknown because a string might be added
@@ -1752,36 +1752,36 @@ TEST(LLVMTypeAnalyzer_ListType, NestedLoopWithTypeChange_AfterWriteInsideInner_N
     List list("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(outerLoop);
 
     // List write inside outer loop
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Inner loop begin
-    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(innerLoop);
 
     // List write inside inner loop
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Inner loop end
-    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(innerEnd);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(outerEnd);
 
     // Returns Unknown because a string might be added
@@ -1795,36 +1795,36 @@ TEST(LLVMTypeAnalyzer_ListType, NestedLoopWithTypeChange_AfterWriteInsideInner_E
     List list("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(outerLoop);
 
     // List write inside outer loop
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Inner loop begin
-    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(innerLoop);
 
     // List write inside inner loop
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Inner loop end
-    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(innerEnd);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(outerEnd);
 
     // Returns Unknown because a string might be added
@@ -1838,36 +1838,36 @@ TEST(LLVMTypeAnalyzer_ListType, NestedLoopWithTypeChange_After_NonEmpty)
     List list("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(outerLoop);
 
     // List write inside outer loop
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Inner loop begin
-    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(innerLoop);
 
     // List write inside inner loop
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
     // Inner loop end
-    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(innerEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(outerEnd);
 
     // Type is not known because the inner loop might not run at all
@@ -1881,36 +1881,36 @@ TEST(LLVMTypeAnalyzer_ListType, NestedLoopWithTypeChange_After_Empty)
     List list("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(outerLoop);
 
     // List write inside outer loop
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Inner loop begin
-    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(innerLoop);
 
     // List write inside inner loop
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
     // Inner loop end
-    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(innerEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(outerEnd);
 
     // Type is not known because the inner loop might not run at all
@@ -1924,36 +1924,36 @@ TEST(LLVMTypeAnalyzer_ListType, NestedLoopWithoutTypeChange_NonEmpty)
     List list("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginWhileLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginWhileLoop, false);
     instructionList.addInstruction(outerLoop);
 
     // List write inside outer loop
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Inner loop begin
-    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(innerLoop);
 
     // List write inside inner loop
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 2.5);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
     // Inner loop end
-    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(innerEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(outerEnd);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
@@ -1966,36 +1966,36 @@ TEST(LLVMTypeAnalyzer_ListType, NestedLoopWithoutTypeChange_Empty)
     List list("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginWhileLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginWhileLoop, false);
     instructionList.addInstruction(outerLoop);
 
     // List write inside outer loop
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Inner loop begin
-    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(innerLoop);
 
     // List write inside inner loop
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 2.5);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
     // Inner loop end
-    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(innerEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(outerEnd);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Number);
@@ -2008,43 +2008,43 @@ TEST(LLVMTypeAnalyzer_ListType, NestedLoopTypeChangesMultipleTimes_NonEmpty)
     List list("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(outerLoop);
 
     // List write inside outer loop
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Inner loop begin
-    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false);
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, false);
     instructionList.addInstruction(innerLoop);
 
     // List write inside inner loop
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
     // Inner loop end
-    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(innerEnd);
 
     // List write after inner loop
-    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value3(Compiler::StaticType::Number, 2);
     appendList3->workList = &list;
     appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     instructionList.addInstruction(appendList3);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(outerEnd);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
@@ -2057,43 +2057,43 @@ TEST(LLVMTypeAnalyzer_ListType, NestedLoopTypeChangesMultipleTimes_Empty)
     List list("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(outerLoop);
 
     // List write inside outer loop
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Inner loop begin
-    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false);
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, false);
     instructionList.addInstruction(innerLoop);
 
     // List write inside inner loop
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
     // Inner loop end
-    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(innerEnd);
 
     // List write after inner loop
-    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value3(Compiler::StaticType::Number, 2);
     appendList3->workList = &list;
     appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     instructionList.addInstruction(appendList3);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(outerEnd);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown);
@@ -2106,51 +2106,51 @@ TEST(LLVMTypeAnalyzer_ListType, MultipleNestedLoopsWithTypeChange_NonEmpty)
     List list("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(outerLoop);
 
     // List write inside outer loop
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Inner loop 1 begin
-    auto innerLoop1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(innerLoop1);
 
     // List write inside inner loop 1
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
     // Inner loop 2 begin
-    auto innerLoop2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(innerLoop2);
 
     // List write inside inner loop 2
-    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value3(Compiler::StaticType::String, "abc");
     appendList3->workList = &list;
     appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     instructionList.addInstruction(appendList3);
 
     // Inner loop 2 end
-    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(innerEnd2);
 
     // Inner loop 1 end
-    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(innerEnd1);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(outerEnd);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
@@ -2163,51 +2163,51 @@ TEST(LLVMTypeAnalyzer_ListType, MultipleNestedLoopsWithTypeChange_Empty)
     List list("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(outerLoop);
 
     // List write inside outer loop
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Inner loop 1 begin
-    auto innerLoop1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(innerLoop1);
 
     // List write inside inner loop 1
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
     // Inner loop 2 begin
-    auto innerLoop2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(innerLoop2);
 
     // List write inside inner loop 2
-    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value3(Compiler::StaticType::String, "abc");
     appendList3->workList = &list;
     appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     instructionList.addInstruction(appendList3);
 
     // Inner loop 2 end
-    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(innerEnd2);
 
     // Inner loop 1 end
-    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(innerEnd1);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(outerEnd);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown);
@@ -2220,51 +2220,51 @@ TEST(LLVMTypeAnalyzer_ListType, MultipleNestedLoopsWithMultipleTypeChanges_NonEm
     List list("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(outerLoop);
 
     // List write inside outer loop
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Inner loop 1 begin
-    auto innerLoop1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(innerLoop1);
 
     // Inner loop 2 begin
-    auto innerLoop2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(innerLoop2);
 
     // List write inside inner loop 2
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "abc");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
     // Inner loop 2 end
-    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(innerEnd2);
 
     // List write inside inner loop 1
-    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value3(Compiler::StaticType::Number, 2.75);
     appendList3->workList = &list;
     appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     instructionList.addInstruction(appendList3);
 
     // Inner loop 1 end
-    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(innerEnd1);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(outerEnd);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
@@ -2277,51 +2277,51 @@ TEST(LLVMTypeAnalyzer_ListType, MultipleNestedLoopsWithMultipleTypeChanges_Empty
     List list("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(outerLoop);
 
     // List write inside outer loop
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Inner loop 1 begin
-    auto innerLoop1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(innerLoop1);
 
     // Inner loop 2 begin
-    auto innerLoop2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(innerLoop2);
 
     // List write inside inner loop 2
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "abc");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
     // Inner loop 2 end
-    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(innerEnd2);
 
     // List write inside inner loop 1
-    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value3(Compiler::StaticType::Number, 2.75);
     appendList3->workList = &list;
     appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     instructionList.addInstruction(appendList3);
 
     // Inner loop 1 end
-    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(innerEnd1);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(outerEnd);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown);
@@ -2334,40 +2334,40 @@ TEST(LLVMTypeAnalyzer_ListType, SameTypeIfElseInLoopWithTypeChange_NonEmpty)
     List list("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(outerLoop);
 
     // Inner if statement begin
-    auto innerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto innerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(innerIf);
 
     // List write inside inner if statement if branch
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "abc");
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Inner if statement else branch
-    auto innerElse = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto innerElse = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(innerElse);
 
     // List write inside inner if statement else branch
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "def");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
     // Inner if statement end
-    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(innerEnd);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(outerEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // A type conflict always occurs
@@ -2380,7 +2380,7 @@ TEST(LLVMTypeAnalyzer_ListType, InsertToList_SameType_NonEmpty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, false);
     LLVMConstantRegister index(Compiler::StaticType::Number, 1);
     LLVMConstantRegister value(Compiler::StaticType::Number, 42.5);
     insertList->workList = &list;
@@ -2388,7 +2388,7 @@ TEST(LLVMTypeAnalyzer_ListType, InsertToList_SameType_NonEmpty)
     insertList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(insertList);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
@@ -2400,7 +2400,7 @@ TEST(LLVMTypeAnalyzer_ListType, InsertToList_DifferentType_Empty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, false);
     LLVMConstantRegister index(Compiler::StaticType::Number, 0);
     LLVMConstantRegister value(Compiler::StaticType::String, "hello");
     insertList->workList = &list;
@@ -2408,7 +2408,7 @@ TEST(LLVMTypeAnalyzer_ListType, InsertToList_DifferentType_Empty)
     insertList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(insertList);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String);
@@ -2420,10 +2420,10 @@ TEST(LLVMTypeAnalyzer_ListType, InsertToList_InLoop_TypeConflict)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto insertList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    auto insertList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, false);
     LLVMConstantRegister index1(Compiler::StaticType::Number, 0);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 123);
     insertList1->workList = &list;
@@ -2431,10 +2431,10 @@ TEST(LLVMTypeAnalyzer_ListType, InsertToList_InLoop_TypeConflict)
     insertList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(insertList1);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
-    auto insertList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    auto insertList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, false);
     LLVMConstantRegister index2(Compiler::StaticType::Number, 1);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     insertList2->workList = &list;
@@ -2442,7 +2442,7 @@ TEST(LLVMTypeAnalyzer_ListType, InsertToList_InLoop_TypeConflict)
     insertList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(insertList2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown);
@@ -2454,7 +2454,7 @@ TEST(LLVMTypeAnalyzer_ListType, ListReplace_SameType_NonEmpty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, false);
     LLVMConstantRegister index(Compiler::StaticType::Number, 0);
     LLVMConstantRegister value(Compiler::StaticType::String, "replaced");
     replaceList->workList = &list;
@@ -2462,7 +2462,7 @@ TEST(LLVMTypeAnalyzer_ListType, ListReplace_SameType_NonEmpty)
     replaceList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(replaceList);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::String);
@@ -2474,7 +2474,7 @@ TEST(LLVMTypeAnalyzer_ListType, ListReplace_DifferentType_NonEmpty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, false);
     LLVMConstantRegister index(Compiler::StaticType::Number, 0);
     LLVMConstantRegister value(Compiler::StaticType::Bool, true);
     replaceList->workList = &list;
@@ -2482,7 +2482,7 @@ TEST(LLVMTypeAnalyzer_ListType, ListReplace_DifferentType_NonEmpty)
     replaceList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(replaceList);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::Unknown);
@@ -2494,7 +2494,7 @@ TEST(LLVMTypeAnalyzer_ListType, ListReplace_WithStringOptimization)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, false);
     LLVMConstantRegister index(Compiler::StaticType::Number, 0);
     LLVMConstantRegister value(Compiler::StaticType::String, "42.75");
     replaceList->workList = &list;
@@ -2502,7 +2502,7 @@ TEST(LLVMTypeAnalyzer_ListType, ListReplace_WithStringOptimization)
     replaceList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(replaceList);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // String "42.75" gets optimized to Number type
@@ -2516,14 +2516,14 @@ TEST(LLVMTypeAnalyzer_ListType, MixedWriteOperations_TypeConflict)
     List list("", "");
 
     // Append a number
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList);
 
     // Insert a string
-    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, false);
     LLVMConstantRegister index(Compiler::StaticType::Number, 0);
     LLVMConstantRegister value2(Compiler::StaticType::String, "hello");
     insertList->workList = &list;
@@ -2532,7 +2532,7 @@ TEST(LLVMTypeAnalyzer_ListType, MixedWriteOperations_TypeConflict)
     instructionList.addInstruction(insertList);
 
     // Replace with a boolean
-    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, false);
     LLVMConstantRegister index2(Compiler::StaticType::Number, 1);
     LLVMConstantRegister value3(Compiler::StaticType::Bool, true);
     replaceList->workList = &list;
@@ -2540,7 +2540,7 @@ TEST(LLVMTypeAnalyzer_ListType, MixedWriteOperations_TypeConflict)
     replaceList->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     instructionList.addInstruction(replaceList);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should be Unknown due to multiple type conflicts
@@ -2554,14 +2554,14 @@ TEST(LLVMTypeAnalyzer_ListType, MixedWriteOperations_SameType)
     List list("", "");
 
     // Append a string
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "hello");
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList);
 
     // Insert another string
-    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, false);
     LLVMConstantRegister index(Compiler::StaticType::Number, 0);
     LLVMConstantRegister value2(Compiler::StaticType::String, "world");
     insertList->workList = &list;
@@ -2570,7 +2570,7 @@ TEST(LLVMTypeAnalyzer_ListType, MixedWriteOperations_SameType)
     instructionList.addInstruction(insertList);
 
     // Replace with another string
-    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, false);
     LLVMConstantRegister index2(Compiler::StaticType::Number, 1);
     LLVMConstantRegister value3(Compiler::StaticType::String, "test");
     replaceList->workList = &list;
@@ -2578,7 +2578,7 @@ TEST(LLVMTypeAnalyzer_ListType, MixedWriteOperations_SameType)
     replaceList->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     instructionList.addInstruction(replaceList);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should be String type since all operations use strings
@@ -2592,14 +2592,14 @@ TEST(LLVMTypeAnalyzer_ListType, ComplexMixedOperations)
     List list("", "");
 
     // Append a number
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 123);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList);
 
     // Insert another number
-    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, false);
     LLVMConstantRegister index1(Compiler::StaticType::Number, 0);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 456);
     insertList->workList = &list;
@@ -2607,11 +2607,11 @@ TEST(LLVMTypeAnalyzer_ListType, ComplexMixedOperations)
     insertList->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(insertList);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Replace with a string (creates type conflict)
-    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, false);
     LLVMConstantRegister index2(Compiler::StaticType::Number, 0);
     LLVMConstantRegister value3(Compiler::StaticType::String, "conflict");
     replaceList->workList = &list;
@@ -2629,18 +2629,18 @@ TEST(LLVMTypeAnalyzer_ListType, ComplexMixedOperations_InLoop)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // Append a number
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 123);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList);
 
     // Insert another number
-    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, false);
     LLVMConstantRegister index1(Compiler::StaticType::Number, 0);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 456);
     insertList->workList = &list;
@@ -2648,11 +2648,11 @@ TEST(LLVMTypeAnalyzer_ListType, ComplexMixedOperations_InLoop)
     insertList->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(insertList);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Replace with a string (creates type conflict)
-    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, false);
     LLVMConstantRegister index2(Compiler::StaticType::Number, 0);
     LLVMConstantRegister value3(Compiler::StaticType::String, "conflict");
     replaceList->workList = &list;
@@ -2660,7 +2660,7 @@ TEST(LLVMTypeAnalyzer_ListType, ComplexMixedOperations_InLoop)
     replaceList->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     instructionList.addInstruction(replaceList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, true), Compiler::StaticType::Unknown);
@@ -2672,33 +2672,33 @@ TEST(LLVMTypeAnalyzer_ListType, MultipleClearsInLoop)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "test");
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
-    clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 5);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Bool, false), Compiler::StaticType::String);
@@ -2711,19 +2711,19 @@ TEST(LLVMTypeAnalyzer_ListType, ClearAndRebuild_WithDifferentTypes)
     List list("", "");
 
     // Initial append
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "initial");
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Clear the list
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
     // Rebuild with different operations and types
-    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, false);
     LLVMConstantRegister index(Compiler::StaticType::Number, 0);
     LLVMConstantRegister value2(Compiler::StaticType::Bool, true);
     insertList->workList = &list;
@@ -2731,7 +2731,7 @@ TEST(LLVMTypeAnalyzer_ListType, ClearAndRebuild_WithDifferentTypes)
     insertList->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(insertList);
 
-    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, false);
     LLVMConstantRegister index2(Compiler::StaticType::Number, 0);
     LLVMConstantRegister value3(Compiler::StaticType::Bool, false);
     replaceList->workList = &list;
@@ -2739,7 +2739,7 @@ TEST(LLVMTypeAnalyzer_ListType, ClearAndRebuild_WithDifferentTypes)
     replaceList->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     instructionList.addInstruction(replaceList);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should be Bool type since clear resets and all subsequent operations use booleans
@@ -2752,25 +2752,25 @@ TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_NewTypeAfterClear_Empty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // Clear the list in the middle of the loop
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
     // Append after clear - this should set the new type
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should return String because the list was empty and append sets the type
@@ -2783,25 +2783,25 @@ TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_NewTypeAfterClear_NonEmpty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // Clear the list in the middle of the loop
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
     // Append after clear - this should set the new type
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should return String because clear makes the list empty, then append sets the type
@@ -2814,32 +2814,32 @@ TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_MultipleAppendsAfterClear)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // Clear the list
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
     // First append after clear
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Second append after clear (same type)
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 3.14);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should return Number because all appends after clear are the same type
@@ -2852,32 +2852,32 @@ TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_TypeConflictAfterClear)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // Clear the list
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
     // First append after clear
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Second append after clear (different type - creates conflict)
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should return Unknown because of type conflict after clear
@@ -2890,16 +2890,16 @@ TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_WithInsertAndReplace)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // Clear the list
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
     // Insert after clear
-    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, false);
     LLVMConstantRegister insertIndex(Compiler::StaticType::Number, 0);
     LLVMConstantRegister insertValue(Compiler::StaticType::Bool, true);
     insertList->workList = &list;
@@ -2908,7 +2908,7 @@ TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_WithInsertAndReplace)
     instructionList.addInstruction(insertList);
 
     // Replace after insert
-    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, false);
     LLVMConstantRegister replaceIndex(Compiler::StaticType::Number, 0);
     LLVMConstantRegister replaceValue(Compiler::StaticType::Bool, false);
     replaceList->workList = &list;
@@ -2916,10 +2916,10 @@ TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_WithInsertAndReplace)
     replaceList->args.push_back({ Compiler::StaticType::Unknown, &replaceValue });
     instructionList.addInstruction(replaceList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should return Bool because all operations after clear use Bool type
@@ -2932,43 +2932,43 @@ TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_ConditionalClear)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // If statement
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // Clear the list conditionally
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
     // Append after clear
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "cleared");
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Else branch
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
     // Append without clearing
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 42);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should return Unknown due to type conflict between branches
@@ -2981,33 +2981,33 @@ TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_AppendAfterClearingInIfBranch_Di
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // If statement
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // Clear the list
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
     // End if statement
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
     // Append
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should return Unknown because the clearing branch might or might not run
@@ -3020,33 +3020,33 @@ TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_AppendAfterClearingInIfBranch_Sa
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // If statement
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // Clear the list
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
     // End if statement
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
     // Append
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 42);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should return Number because there are no type conflicts
@@ -3059,37 +3059,37 @@ TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_AppendAfterClearingInElseBranch_
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // If statement
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // Else branch
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
     // Clear the list
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
     // End if statement
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
     // Append
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should return Unknown because the clearing branch might or might not run
@@ -3102,37 +3102,37 @@ TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_AppendAfterClearingInElseBranch_
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // If statement
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // Else branch
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
     // Clear the list
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
     // End if statement
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
     // Append
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 42);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should return Number because there are no type conflicts
@@ -3145,37 +3145,37 @@ TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_MultipleClearsAndWrites)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // First clear
-    auto clearList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList1->workList = &list;
     instructionList.addInstruction(clearList1);
 
     // Append after first clear
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "first");
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Second clear
-    auto clearList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList2->workList = &list;
     instructionList.addInstruction(clearList2);
 
     // Append after second clear (different type)
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 42);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should return Number because the last clear+append sequence determines the final type
@@ -3188,18 +3188,18 @@ TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_ClearWithoutSubsequentWrite)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // Clear the list but don't write anything after
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should return previous type since no writes occurred after clear
@@ -3212,31 +3212,31 @@ TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_ClearInNestedIf)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // Nested if statement
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // Clear and write in nested if
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::Bool, true);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should return Unknown because the type-changing branch might or might not run
@@ -3249,38 +3249,38 @@ TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_AppendToEmptyListAndClearInIfBra
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // Append in if branch
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Clear the list in if branch
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
     // Append after if statement - should change type
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should return String because the list remains empty after the if statement
@@ -3293,38 +3293,38 @@ TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_AppendToEmptyListAndClearInIfBra
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // Append in if branch
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Bool, true);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Clear the list in if branch
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
     // Append after if statement - should change type
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should return String because the list remains empty after the if statement
@@ -3337,41 +3337,41 @@ TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_AppendToEmptyListAndClearInElseB
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
     // Append in else branch
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Clear the list in else branch
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
     // Append after if statement - should change type
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should return String because the list remains empty after the if statement
@@ -3384,41 +3384,41 @@ TEST(LLVMTypeAnalyzer_ListType, ClearListInLoop_AppendToEmptyListAndClearInElseB
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
     // Append in else branch
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Bool, true);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Clear the list in else branch
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
     // Append after if statement - should change type
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should return String because the list remains empty after the if statement
@@ -3433,18 +3433,18 @@ TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_SimpleRead_NonEmpty)
     List targetList("target", "");
 
     // Establish source list type
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &sourceList;
     instructionList.addInstruction(clearList);
 
-    auto appendSource = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendSource = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister sourceValue(Compiler::StaticType::String, "hello");
     appendSource->workList = &sourceList;
     appendSource->args.push_back({ Compiler::StaticType::Unknown, &sourceValue });
     instructionList.addInstruction(appendSource);
 
     // Read from source list and write to target list
-    auto readSource = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readSource = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, false);
     auto readSourceReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
     readSourceReg->instruction = readSource;
     readSourceReg->isRawValue = false;
@@ -3454,12 +3454,12 @@ TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_SimpleRead_NonEmpty)
     readSource->args.push_back({ Compiler::StaticType::Number, &index });
     instructionList.addInstruction(readSource);
 
-    auto appendTarget = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendTarget = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     appendTarget->workList = &targetList;
     appendTarget->args.push_back({ Compiler::StaticType::Unknown, readSourceReg.get() });
     instructionList.addInstruction(appendTarget);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(&targetList, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
@@ -3473,18 +3473,18 @@ TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_SimpleRead_Empty)
     List targetList("target", "");
 
     // Establish source list type
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &sourceList;
     instructionList.addInstruction(clearList);
 
-    auto appendSource = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendSource = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister sourceValue(Compiler::StaticType::Bool, true);
     appendSource->workList = &sourceList;
     appendSource->args.push_back({ Compiler::StaticType::Unknown, &sourceValue });
     instructionList.addInstruction(appendSource);
 
     // Read from source list and write to target list
-    auto readSource = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readSource = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, false);
     auto readSourceReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
     readSourceReg->instruction = readSource;
     readSourceReg->isRawValue = false;
@@ -3494,12 +3494,12 @@ TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_SimpleRead_Empty)
     readSource->args.push_back({ Compiler::StaticType::Number, &index });
     instructionList.addInstruction(readSource);
 
-    auto appendTarget = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendTarget = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     appendTarget->workList = &targetList;
     appendTarget->args.push_back({ Compiler::StaticType::Unknown, readSourceReg.get() });
     instructionList.addInstruction(appendTarget);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(&targetList, funcCall.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Bool);
@@ -3512,23 +3512,23 @@ TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_InLoop_TypeConflict)
     List sourceList("source", "");
     List targetList("target", "");
 
-    auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(loopStart);
 
     // Clear source list
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &sourceList;
     instructionList.addInstruction(clearList);
 
     // First iteration: append string to source
-    auto appendSource1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendSource1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister sourceValue1(Compiler::StaticType::String, "text");
     appendSource1->workList = &sourceList;
     appendSource1->args.push_back({ Compiler::StaticType::Unknown, &sourceValue1 });
     instructionList.addInstruction(appendSource1);
 
     // Read from source and write to target
-    auto readSource1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readSource1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, false);
     auto readSource1Reg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
     readSource1Reg->instruction = readSource1;
     readSource1Reg->isRawValue = false;
@@ -3538,20 +3538,20 @@ TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_InLoop_TypeConflict)
     readSource1->args.push_back({ Compiler::StaticType::Number, &index1 });
     instructionList.addInstruction(readSource1);
 
-    auto appendTarget1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendTarget1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     appendTarget1->workList = &targetList;
     appendTarget1->args.push_back({ Compiler::StaticType::Unknown, readSource1Reg.get() });
     instructionList.addInstruction(appendTarget1);
 
     // Second iteration: append number to source (creates type conflict)
-    auto appendSource2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendSource2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister sourceValue2(Compiler::StaticType::Number, 42);
     appendSource2->workList = &sourceList;
     appendSource2->args.push_back({ Compiler::StaticType::Unknown, &sourceValue2 });
     instructionList.addInstruction(appendSource2);
 
     // Read from source and write to target
-    auto readSource2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readSource2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, false);
     auto readSource2Reg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
     readSource2Reg->instruction = readSource2;
     readSource2Reg->isRawValue = false;
@@ -3561,15 +3561,15 @@ TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_InLoop_TypeConflict)
     readSource2->args.push_back({ Compiler::StaticType::Number, &index2 });
     instructionList.addInstruction(readSource2);
 
-    auto appendTarget2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendTarget2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     appendTarget2->workList = &targetList;
     appendTarget2->args.push_back({ Compiler::StaticType::Unknown, readSource2Reg.get() });
     instructionList.addInstruction(appendTarget2);
 
-    auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(loopEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(&targetList, funcCall.get(), Compiler::StaticType::String, true), Compiler::StaticType::Unknown);
@@ -3582,18 +3582,18 @@ TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_InLoop_ConsistentType_NonEmp
     List sourceList("source", "");
     List targetList("target", "");
 
-    auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(loopStart);
 
     // Append number to source
-    auto appendSource = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendSource = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister sourceValue(Compiler::StaticType::Number, 3.14);
     appendSource->workList = &sourceList;
     appendSource->args.push_back({ Compiler::StaticType::Unknown, &sourceValue });
     instructionList.addInstruction(appendSource);
 
     // Read from source and write to target
-    auto readSource = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readSource = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, false);
     auto readSourceReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
     readSourceReg->instruction = readSource;
     readSourceReg->isRawValue = false;
@@ -3603,15 +3603,15 @@ TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_InLoop_ConsistentType_NonEmp
     readSource->args.push_back({ Compiler::StaticType::Number, &index });
     instructionList.addInstruction(readSource);
 
-    auto appendTarget = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendTarget = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     appendTarget->workList = &targetList;
     appendTarget->args.push_back({ Compiler::StaticType::Unknown, readSourceReg.get() });
     instructionList.addInstruction(appendTarget);
 
-    auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(loopEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(&targetList, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
@@ -3624,22 +3624,22 @@ TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_InLoop_ConsistentType_EmptyS
     List sourceList("source", "");
     List targetList("target", "");
 
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &sourceList;
     instructionList.addInstruction(clearList);
 
-    auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(loopStart);
 
     // Append number to source
-    auto appendSource = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendSource = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister sourceValue(Compiler::StaticType::Number, 3.14);
     appendSource->workList = &sourceList;
     appendSource->args.push_back({ Compiler::StaticType::Unknown, &sourceValue });
     instructionList.addInstruction(appendSource);
 
     // Read from source and write to target
-    auto readSource = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readSource = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, false);
     auto readSourceReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
     readSourceReg->instruction = readSource;
     readSourceReg->isRawValue = false;
@@ -3649,15 +3649,15 @@ TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_InLoop_ConsistentType_EmptyS
     readSource->args.push_back({ Compiler::StaticType::Number, &index });
     instructionList.addInstruction(readSource);
 
-    auto appendTarget = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendTarget = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     appendTarget->workList = &targetList;
     appendTarget->args.push_back({ Compiler::StaticType::Unknown, readSourceReg.get() });
     instructionList.addInstruction(appendTarget);
 
-    auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(loopEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(&targetList, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
@@ -3670,23 +3670,23 @@ TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_Circular_TypeSafety)
     List listA("listA", "");
     List listB("listB", "");
 
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &listA;
     instructionList.addInstruction(clearList);
 
-    clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &listB;
     instructionList.addInstruction(clearList);
 
     // Initialize listA with a number
-    auto appendA1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendA1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister valueA1(Compiler::StaticType::Number, 10);
     appendA1->workList = &listA;
     appendA1->args.push_back({ Compiler::StaticType::Unknown, &valueA1 });
     instructionList.addInstruction(appendA1);
 
     // Read from listA and write to listB
-    auto readA = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readA = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, false);
     auto readAReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
     readAReg->instruction = readA;
     readAReg->isRawValue = false;
@@ -3696,13 +3696,13 @@ TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_Circular_TypeSafety)
     readA->args.push_back({ Compiler::StaticType::Number, &indexA });
     instructionList.addInstruction(readA);
 
-    auto appendB = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendB = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     appendB->workList = &listB;
     appendB->args.push_back({ Compiler::StaticType::Unknown, readAReg.get() });
     instructionList.addInstruction(appendB);
 
     // Read from listB and write back to listA (circular dependency)
-    auto readB = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readB = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, false);
     auto readBReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
     readBReg->instruction = readB;
     readBReg->isRawValue = false;
@@ -3712,12 +3712,12 @@ TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_Circular_TypeSafety)
     readB->args.push_back({ Compiler::StaticType::Number, &indexB });
     instructionList.addInstruction(readB);
 
-    auto appendA2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendA2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     appendA2->workList = &listA;
     appendA2->args.push_back({ Compiler::StaticType::Unknown, readBReg.get() });
     instructionList.addInstruction(appendA2);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(&listA, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
@@ -3730,26 +3730,26 @@ TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_Circular_TypeSafety_InLoop)
     List listA("listA", "");
     List listB("listB", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &listA;
     instructionList.addInstruction(clearList);
 
-    clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &listB;
     instructionList.addInstruction(clearList);
 
     // Initialize listA with a number
-    auto appendA1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendA1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister valueA1(Compiler::StaticType::Number, 10);
     appendA1->workList = &listA;
     appendA1->args.push_back({ Compiler::StaticType::Unknown, &valueA1 });
     instructionList.addInstruction(appendA1);
 
     // Read from listA and write to listB
-    auto readA = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readA = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, false);
     auto readAReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
     readAReg->instruction = readA;
     readAReg->isRawValue = false;
@@ -3759,13 +3759,13 @@ TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_Circular_TypeSafety_InLoop)
     readA->args.push_back({ Compiler::StaticType::Number, &indexA });
     instructionList.addInstruction(readA);
 
-    auto appendB = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendB = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     appendB->workList = &listB;
     appendB->args.push_back({ Compiler::StaticType::Unknown, readAReg.get() });
     instructionList.addInstruction(appendB);
 
     // Read from listB and write back to listA (circular dependency)
-    auto readB = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readB = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, false);
     auto readBReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
     readBReg->instruction = readB;
     readBReg->isRawValue = false;
@@ -3775,15 +3775,15 @@ TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_Circular_TypeSafety_InLoop)
     readB->args.push_back({ Compiler::StaticType::Number, &indexB });
     instructionList.addInstruction(readB);
 
-    auto appendA2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendA2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     appendA2->workList = &listA;
     appendA2->args.push_back({ Compiler::StaticType::Unknown, readBReg.get() });
     instructionList.addInstruction(appendA2);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listType(&listA, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::Number);
@@ -3796,26 +3796,26 @@ TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_Circular_TypeConflict)
     List listA("listA", "");
     List listB("listB", "");
 
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &listA;
     instructionList.addInstruction(clearList);
 
-    clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &listB;
     instructionList.addInstruction(clearList);
 
-    auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(loopStart);
 
     // Initialize listA with a number
-    auto appendA1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendA1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister valueA1(Compiler::StaticType::Number, 10);
     appendA1->workList = &listA;
     appendA1->args.push_back({ Compiler::StaticType::Unknown, &valueA1 });
     instructionList.addInstruction(appendA1);
 
     // Read from listA and write to listB
-    auto readA = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readA = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, false);
     auto readAReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
     readAReg->instruction = readA;
     readAReg->isRawValue = false;
@@ -3825,20 +3825,20 @@ TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_Circular_TypeConflict)
     readA->args.push_back({ Compiler::StaticType::Number, &indexA });
     instructionList.addInstruction(readA);
 
-    auto appendB = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendB = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     appendB->workList = &listB;
     appendB->args.push_back({ Compiler::StaticType::Unknown, readAReg.get() });
     instructionList.addInstruction(appendB);
 
     // Create type conflict by appending string to listB
-    auto appendB2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendB2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister valueB2(Compiler::StaticType::String, "conflict");
     appendB2->workList = &listB;
     appendB2->args.push_back({ Compiler::StaticType::Unknown, &valueB2 });
     instructionList.addInstruction(appendB2);
 
     // Read from listB and write back to listA (circular dependency with type conflict)
-    auto readB = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readB = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, false);
     auto readBReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
     readBReg->instruction = readB;
     readBReg->isRawValue = false;
@@ -3848,15 +3848,15 @@ TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_Circular_TypeConflict)
     readB->args.push_back({ Compiler::StaticType::Number, &indexB });
     instructionList.addInstruction(readB);
 
-    auto appendA2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendA2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     appendA2->workList = &listA;
     appendA2->args.push_back({ Compiler::StaticType::Unknown, readBReg.get() });
     instructionList.addInstruction(appendA2);
 
-    auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(loopEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should return Unknown due to circular dependency with type conflicts
@@ -3869,19 +3869,19 @@ TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_Circular_SingleList_KnownTyp
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
     // Initialize list with a number
-    auto append1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto append1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 10);
     append1->workList = &list;
     append1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(append1);
 
     // Read from list and write to list
-    auto read = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto read = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, false);
     auto readReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
     readReg->instruction = read;
     readReg->isRawValue = false;
@@ -3891,12 +3891,12 @@ TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_Circular_SingleList_KnownTyp
     read->args.push_back({ Compiler::StaticType::Number, &index });
     instructionList.addInstruction(read);
 
-    auto append2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto append2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     append2->workList = &list;
     append2->args.push_back({ Compiler::StaticType::Unknown, readReg.get() });
     instructionList.addInstruction(append2);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::String, false), Compiler::StaticType::Number);
@@ -3909,7 +3909,7 @@ TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_Circular_SingleList_KnownTyp
     List list("", "");
 
     // Read from list and write to list
-    auto read = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto read = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, false);
     auto readReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
     readReg->instruction = read;
     readReg->isRawValue = false;
@@ -3919,12 +3919,12 @@ TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_Circular_SingleList_KnownTyp
     read->args.push_back({ Compiler::StaticType::Number, &index });
     instructionList.addInstruction(read);
 
-    auto append2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto append2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     append2->workList = &list;
     append2->args.push_back({ Compiler::StaticType::Unknown, readReg.get() });
     instructionList.addInstruction(append2);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
@@ -3937,7 +3937,7 @@ TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_Circular_SingleList_UnknownT
     List list("", "");
 
     // Read from list and write to list
-    auto read = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto read = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, false);
     auto readReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
     readReg->instruction = read;
     readReg->isRawValue = false;
@@ -3947,12 +3947,12 @@ TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_Circular_SingleList_UnknownT
     read->args.push_back({ Compiler::StaticType::Number, &index });
     instructionList.addInstruction(read);
 
-    auto append2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto append2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     append2->workList = &list;
     append2->args.push_back({ Compiler::StaticType::Unknown, readReg.get() });
     instructionList.addInstruction(append2);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.listType(&list, funcCall.get(), Compiler::StaticType::Unknown, false), Compiler::StaticType::Unknown);
@@ -3967,23 +3967,23 @@ TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_ChainedReads_TypePropagation
     List listC("listC", "");
 
     // Clear lists
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &listA;
     instructionList.addInstruction(clearList);
 
-    clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &listB;
     instructionList.addInstruction(clearList);
 
     // Initialize listA with a boolean
-    auto appendA = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendA = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister valueA(Compiler::StaticType::Bool, false);
     appendA->workList = &listA;
     appendA->args.push_back({ Compiler::StaticType::Unknown, &valueA });
     instructionList.addInstruction(appendA);
 
     // Read from listA and write to listB
-    auto readA = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readA = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, false);
     auto readAReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
     readAReg->instruction = readA;
     readAReg->isRawValue = false;
@@ -3993,13 +3993,13 @@ TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_ChainedReads_TypePropagation
     readA->args.push_back({ Compiler::StaticType::Number, &indexA });
     instructionList.addInstruction(readA);
 
-    auto appendB = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendB = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     appendB->workList = &listB;
     appendB->args.push_back({ Compiler::StaticType::Unknown, readAReg.get() });
     instructionList.addInstruction(appendB);
 
     // Read from listB and write to listC
-    auto readB = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readB = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, false);
     auto readBReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
     readBReg->instruction = readB;
     readBReg->isRawValue = false;
@@ -4009,12 +4009,12 @@ TEST(LLVMTypeAnalyzer_ListType, CrossListDependency_ChainedReads_TypePropagation
     readB->args.push_back({ Compiler::StaticType::Number, &indexB });
     instructionList.addInstruction(readB);
 
-    auto appendC = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendC = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     appendC->workList = &listC;
     appendC->args.push_back({ Compiler::StaticType::Unknown, readBReg.get() });
     instructionList.addInstruction(appendC);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Type should propagate through the chain: A -> B -> C
diff --git a/test/llvm/type_analyzer/listtypeafterbranch_test.cpp b/test/llvm/type_analyzer/listtypeafterbranch_test.cpp
index 5da22fd2..bf9c667b 100644
--- a/test/llvm/type_analyzer/listtypeafterbranch_test.cpp
+++ b/test/llvm/type_analyzer/listtypeafterbranch_test.cpp
@@ -18,13 +18,13 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, NullList)
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(nullptr, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
@@ -43,10 +43,10 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, EmptyLoop)
     List list("", "");
     LLVMInstructionList instructionList;
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
@@ -58,10 +58,10 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, EmptyIfStatement)
     List list("", "");
     LLVMInstructionList instructionList;
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(start);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
@@ -73,13 +73,13 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, EmptyIfElseStatement_IfBranch)
     List list("", "");
     LLVMInstructionList instructionList;
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(start);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
@@ -91,13 +91,13 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, EmptyIfElseStatement_ElseBranch)
     List list("", "");
     LLVMInstructionList instructionList;
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(start);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, elseStart.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
@@ -109,10 +109,10 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, EmptyLoopUnknownType)
     List list("", "");
     LLVMInstructionList instructionList;
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Unknown, false), Compiler::StaticType::Unknown);
@@ -124,13 +124,13 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, NoWriteOperations)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
@@ -142,16 +142,16 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendSameTypeNumber)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 1.25);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
@@ -163,16 +163,16 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendSameTypeBool)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::Bool, true);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Bool, false), Compiler::StaticType::Bool);
@@ -184,16 +184,16 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendSameTypeString)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, false), Compiler::StaticType::String);
@@ -205,16 +205,16 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendStringOptimization)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "1.25");
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // Although string is appended, it's constant and represents a number
@@ -228,24 +228,24 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendMultipleLists)
     List list1("", "");
     List list2("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // Append to list1
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 6);
     appendList1->workList = &list1;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Append to list2
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     appendList2->workList = &list2;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list1, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
@@ -257,16 +257,16 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendFromUnknownType)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMRegister value(Compiler::StaticType::Unknown);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
@@ -278,16 +278,16 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendToUnknownType)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 5);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Unknown, false), Compiler::StaticType::Unknown);
@@ -299,16 +299,16 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendUnknownToUnknownType)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMRegister value(Compiler::StaticType::Unknown);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Unknown, false), Compiler::StaticType::Unknown);
@@ -320,10 +320,10 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleInsertSameType)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, false);
     LLVMConstantRegister index(Compiler::StaticType::Number, 1);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     appendList->workList = &list;
@@ -331,7 +331,7 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleInsertSameType)
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, false), Compiler::StaticType::String);
@@ -343,10 +343,10 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleReplaceSameType)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, false);
     LLVMConstantRegister index(Compiler::StaticType::Number, 1);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     appendList->workList = &list;
@@ -354,7 +354,7 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleReplaceSameType)
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, false), Compiler::StaticType::String);
@@ -366,16 +366,16 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeNumberToStri
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::String);
@@ -387,16 +387,16 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeNumberToStri
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
@@ -408,16 +408,16 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeStringToNumb
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 5.8);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, true), Compiler::StaticType::Number);
@@ -429,16 +429,16 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeStringToNumb
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 5.8);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, false), Compiler::StaticType::Unknown);
@@ -450,16 +450,16 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeNumberToBool
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::Bool, true);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Bool);
@@ -471,16 +471,16 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeNumberToBool
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::Bool, true);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
@@ -492,16 +492,16 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeBoolToNumber
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 1);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Bool, true), Compiler::StaticType::Number);
@@ -513,16 +513,16 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeBoolToNumber
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 1);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Bool, false), Compiler::StaticType::Unknown);
@@ -534,16 +534,16 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeBoolToString
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "abc");
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Bool, true), Compiler::StaticType::String);
@@ -555,16 +555,16 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeBoolToString
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "abc");
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Bool, false), Compiler::StaticType::Unknown);
@@ -576,16 +576,16 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeStringToBool
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::Bool, false);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, true), Compiler::StaticType::Bool);
@@ -597,16 +597,16 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentTypeStringToBool
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::Bool, false);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, false), Compiler::StaticType::Unknown);
@@ -618,16 +618,16 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendSameType_IfStatement)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 1.25);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
@@ -639,16 +639,16 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentType_IfStatement
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 5.8);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, true), Compiler::StaticType::Number);
@@ -660,16 +660,16 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleAppendDifferentType_IfStatement
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 5.8);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::String, false), Compiler::StaticType::Unknown);
@@ -681,10 +681,10 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleInsertDifferentType_Empty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, false);
     LLVMConstantRegister index(Compiler::StaticType::Number, 1);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     appendList->workList = &list;
@@ -692,7 +692,7 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleInsertDifferentType_Empty)
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // Insert might be a no-op depending on the index
@@ -705,10 +705,10 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleInsertDifferentType_Empty_Unkno
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, false);
     LLVMConstantRegister index(Compiler::StaticType::Number, 1);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     appendList->workList = &list;
@@ -716,7 +716,7 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleInsertDifferentType_Empty_Unkno
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // Insert might be a no-op depending on the index
@@ -729,10 +729,10 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleInsertDifferentType_NonEmpty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, false);
     LLVMConstantRegister index(Compiler::StaticType::Number, 1);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     appendList->workList = &list;
@@ -740,7 +740,7 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleInsertDifferentType_NonEmpty)
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
@@ -752,10 +752,10 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleReplaceDifferentType_Empty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, false);
     LLVMConstantRegister index(Compiler::StaticType::Number, 1);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     appendList->workList = &list;
@@ -763,7 +763,7 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleReplaceDifferentType_Empty)
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // Since the list is empty, it's safe to return any type
@@ -777,10 +777,10 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleReplaceDifferentType_NonEmpty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, false);
     LLVMConstantRegister index(Compiler::StaticType::Number, 1);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     appendList->workList = &list;
@@ -788,7 +788,7 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, SingleReplaceDifferentType_NonEmpty)
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
@@ -800,24 +800,24 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleAppendsDifferentTypes_Empty)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // First append: string "abc" (incompatible with Number)
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "abc");
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Second append: number 5.25 (compatible with Number pre-loop type)
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 5.25);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // Should return Unknown because first append creates type conflict with pre-loop Number type
@@ -830,24 +830,24 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleAppendsDifferentTypes_NonEmpt
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // First append: string "abc" (incompatible with Number)
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "abc");
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Second append: number 5.25 (compatible with Number pre-loop type)
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 5.25);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // Should return Unknown because first append creates type conflict with pre-loop Number type
@@ -860,24 +860,24 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleAppendsWithStringOptimization
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // First append: number 2 (compatible with Number)
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 2);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Second append: string "3.14" (optimized to Number, compatible with pre-loop type)
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "3.14");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // Should return Number because final append is optimized to Number type
@@ -890,24 +890,24 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleAppendsDifferentTypes_IfState
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(start);
 
     // First append: string "abc" (incompatible with Number)
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "abc");
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Second append: number 5.25 (compatible with Number type)
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 5.25);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(end);
 
     // Should return Unknown because first append creates type conflict with Number type
@@ -920,34 +920,34 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleAppendsDifferentTypes_IfBranc
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(start);
 
     // First append: string "abc" (incompatible with Number)
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "abc");
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Second append: number 5.25 (compatible with Number type)
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 5.25);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
     // Else branch append: string "test" (incompatible with Number type)
-    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value3(Compiler::StaticType::String, "test");
     appendList3->workList = &list;
     appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     instructionList.addInstruction(appendList3);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(end);
 
     // Should return Unknown because first append in if branch creates type conflict
@@ -960,34 +960,34 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleAppendsSameType_ElseBranch)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(start);
 
     // First append: string "abc" (incompatible with Number)
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "abc");
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
     // Else branch first append: string "abc" (incompatible with Number)
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "abc");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
     // Else branch second append: number 5.25 (compatible with Number type)
-    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value3(Compiler::StaticType::Number, 5.25);
     appendList3->workList = &list;
     appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     instructionList.addInstruction(appendList3);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(end);
 
     // Should return Unknown because first append in else branch creates type conflict
@@ -1000,33 +1000,33 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, IfStatementInLoop_TypeChangeInIfBranc
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // First append - changes type
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "test");
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
     // Second append - does not change type
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 42);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // Returns unknown type because the type-changing branch might or might not run
@@ -1039,33 +1039,33 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, IfStatementInLoop_TypeChangeInElseBra
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // First append - does not change type
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
     // Second append - changes type
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // Returns unknown type because the type-changing branch might or might not run
@@ -1078,33 +1078,33 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, IfStatementInLoop_IfElseWithoutTypeCh
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // First append - does not change type
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
     // Second append - does not change type
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
@@ -1116,11 +1116,11 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleInsertsDifferentTypes)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // First insert: number
-    auto insertList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    auto insertList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, false);
     LLVMConstantRegister index1(Compiler::StaticType::Number, 1);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
     insertList1->workList = &list;
@@ -1129,7 +1129,7 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleInsertsDifferentTypes)
     instructionList.addInstruction(insertList1);
 
     // Second insert: string (creates type conflict)
-    auto insertList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    auto insertList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, false);
     LLVMConstantRegister index2(Compiler::StaticType::Number, 1);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     insertList2->workList = &list;
@@ -1137,7 +1137,7 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleInsertsDifferentTypes)
     insertList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(insertList2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown);
@@ -1149,11 +1149,11 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleReplacesDifferentTypes)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // First replace: compatible with Bool
-    auto replaceList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    auto replaceList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, false);
     LLVMConstantRegister index1(Compiler::StaticType::Number, 1);
     LLVMConstantRegister value1(Compiler::StaticType::Bool, true);
     replaceList1->workList = &list;
@@ -1162,7 +1162,7 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleReplacesDifferentTypes)
     instructionList.addInstruction(replaceList1);
 
     // Second replace: incompatible with Bool
-    auto replaceList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    auto replaceList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, false);
     LLVMConstantRegister index2(Compiler::StaticType::Number, 2);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     replaceList2->workList = &list;
@@ -1170,7 +1170,7 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleReplacesDifferentTypes)
     replaceList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(replaceList2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, start.get(), Compiler::StaticType::Bool, false), Compiler::StaticType::Unknown);
@@ -1182,18 +1182,18 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CombinedAppendInsertReplace_SameTypes
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // First: append number (compatible with Number)
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister appendValue(Compiler::StaticType::Number, 42);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &appendValue });
     instructionList.addInstruction(appendList);
 
     // Second: insert number (compatible with Number)
-    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, false);
     LLVMConstantRegister insertIndex(Compiler::StaticType::Number, 1);
     LLVMConstantRegister insertValue(Compiler::StaticType::Number, 5);
     insertList->workList = &list;
@@ -1202,7 +1202,7 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CombinedAppendInsertReplace_SameTypes
     instructionList.addInstruction(insertList);
 
     // Third: replace with number (compatible with Number)
-    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, false);
     LLVMConstantRegister replaceIndex(Compiler::StaticType::Number, 2);
     LLVMConstantRegister replaceValue(Compiler::StaticType::Number, 3.14);
     replaceList->workList = &list;
@@ -1210,7 +1210,7 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CombinedAppendInsertReplace_SameTypes
     replaceList->args.push_back({ Compiler::StaticType::Unknown, &replaceValue });
     instructionList.addInstruction(replaceList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // Should return Number because only numbers are used
@@ -1223,18 +1223,18 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CombinedAppendInsertReplace_TypeConfl
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // First: append number (compatible with Number)
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister appendValue(Compiler::StaticType::Number, 42);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &appendValue });
     instructionList.addInstruction(appendList);
 
     // Second: insert string (creates type conflict)
-    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, false);
     LLVMConstantRegister insertIndex(Compiler::StaticType::Number, 0);
     LLVMConstantRegister insertValue(Compiler::StaticType::String, "hello");
     insertList->workList = &list;
@@ -1243,7 +1243,7 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CombinedAppendInsertReplace_TypeConfl
     instructionList.addInstruction(insertList);
 
     // Third: replace with number (still conflicted)
-    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, false);
     LLVMConstantRegister replaceIndex(Compiler::StaticType::Number, 1);
     LLVMConstantRegister replaceValue(Compiler::StaticType::Number, 3.14);
     replaceList->workList = &list;
@@ -1251,7 +1251,7 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CombinedAppendInsertReplace_TypeConfl
     replaceList->args.push_back({ Compiler::StaticType::Unknown, &replaceValue });
     instructionList.addInstruction(replaceList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // Should return Unknown because insert created type conflict
@@ -1265,33 +1265,33 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, NestedLoopWithTypeChange)
     List list("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(outerLoop);
 
     // List append inside outer loop
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Inner loop begin
-    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(innerLoop);
 
     // List append inside inner loop (creates type conflict)
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
     // Inner loop end
-    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(innerEnd);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(outerEnd);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, outerLoop.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
@@ -1304,33 +1304,33 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, NestedLoopWithoutTypeChange)
     List list("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginWhileLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginWhileLoop, false);
     instructionList.addInstruction(outerLoop);
 
     // List append inside outer loop
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Inner loop begin
-    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(innerLoop);
 
     // List append inside inner loop (same type)
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 2.5);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
     // Inner loop end
-    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(innerEnd);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(outerEnd);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, outerLoop.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
@@ -1343,33 +1343,33 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, NestedLoopWithTypeChangeBeforeLoop)
     List list("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, false);
     instructionList.addInstruction(outerLoop);
 
     // List append inside outer loop (creates type conflict)
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "test");
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Inner loop begin
-    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(innerLoop);
 
     // List append inside inner loop
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 5);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
     // Inner loop end
-    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(innerEnd);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(outerEnd);
 
     // Returns unknown type because first append creates type conflict
@@ -1383,37 +1383,37 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, IfStatementInLoopWithTypeChangeBefore
     List list("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, false);
     instructionList.addInstruction(outerLoop);
 
     // List append inside outer loop (creates type conflict)
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "test");
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Inner if statement begin
-    auto innerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto innerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(innerIf);
 
     // List append inside inner if statement if branch
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 5);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
     // Inner if statement else branch begin
-    auto innerElse = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto innerElse = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(innerElse);
 
     // Inner if statement end
-    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(innerEnd);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(outerEnd);
 
     // Returns unknown type because first append already created type conflict
@@ -1427,48 +1427,48 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleNestedLoopsWithTypeChange)
     List list("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(outerLoop);
 
     // List append inside outer loop
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Inner loop 1 begin
-    auto innerLoop1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(innerLoop1);
 
     // List append inside inner loop 1
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
     // Inner loop 2 begin
-    auto innerLoop2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(innerLoop2);
 
     // List append inside inner loop 2 (creates type conflict)
-    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value3(Compiler::StaticType::String, "abc");
     appendList3->workList = &list;
     appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     instructionList.addInstruction(appendList3);
 
     // Inner loop 2 end
-    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(innerEnd2);
 
     // Inner loop 1 end
-    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(innerEnd1);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(outerEnd);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, outerLoop.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
@@ -1481,59 +1481,59 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleNestedIfStatementsWithTypeCha
     List list("", "");
 
     // Outer if statement begin
-    auto outerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto outerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(outerIf);
 
     // List append inside outer if statement
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Inner if statement 1 begin
-    auto innerIf1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto innerIf1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(innerIf1);
 
     // List append inside inner if statement 1
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
     // Inner if statement 2 begin
-    auto innerIf2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto innerIf2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(innerIf2);
 
     // List append inside inner if statement 2 (creates type conflict)
-    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value3(Compiler::StaticType::String, "abc");
     appendList3->workList = &list;
     appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     instructionList.addInstruction(appendList3);
 
     // Inner if statement 2 else branch
-    auto innerElse2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto innerElse2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(innerElse2);
 
     // List append inside inner if statement 2 else branch
-    auto appendList4 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList4 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value4(Compiler::StaticType::Number, 4);
     appendList4->workList = &list;
     appendList4->args.push_back({ Compiler::StaticType::Unknown, &value4 });
     instructionList.addInstruction(appendList4);
 
     // Inner if statement 2 end
-    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(innerEnd2);
 
     // Inner if statement 1 end
-    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(innerEnd1);
 
     // Outer if statement end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(outerEnd);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, outerIf.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
@@ -1546,59 +1546,59 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleNestedIfStatementsWithTypeCha
     List list("", "");
 
     // Outer if statement begin
-    auto outerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto outerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(outerIf);
 
     // List append inside outer if statement
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Inner if statement 1 begin
-    auto innerIf1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto innerIf1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(innerIf1);
 
     // List append inside inner if statement 1
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
     // Inner if statement 2 begin
-    auto innerIf2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto innerIf2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(innerIf2);
 
     // List append inside inner if statement 2
-    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value3(Compiler::StaticType::Number, 4);
     appendList3->workList = &list;
     appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     instructionList.addInstruction(appendList3);
 
     // Inner if statement 2 else branch
-    auto innerElse2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto innerElse2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(innerElse2);
 
     // List append inside inner if statement 2 else branch (creates type conflict)
-    auto appendList4 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList4 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value4(Compiler::StaticType::String, "abc");
     appendList4->workList = &list;
     appendList4->args.push_back({ Compiler::StaticType::Unknown, &value4 });
     instructionList.addInstruction(appendList4);
 
     // Inner if statement 2 end
-    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(innerEnd2);
 
     // Inner if statement 1 end
-    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(innerEnd1);
 
     // Outer if statement end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(outerEnd);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, outerIf.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Unknown);
@@ -1611,59 +1611,59 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, MultipleNestedIfStatementsWithoutType
     List list("", "");
 
     // Outer if statement begin
-    auto outerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto outerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(outerIf);
 
     // List append inside outer if statement
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Inner if statement 1 begin
-    auto innerIf1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto innerIf1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(innerIf1);
 
     // List append inside inner if statement 1
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
     // Inner if statement 2 begin
-    auto innerIf2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto innerIf2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(innerIf2);
 
     // List append inside inner if statement 2
-    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value3(Compiler::StaticType::Number, 4);
     appendList3->workList = &list;
     appendList3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     instructionList.addInstruction(appendList3);
 
     // Inner if statement 2 else branch
-    auto innerElse2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto innerElse2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(innerElse2);
 
     // List append inside inner if statement 2 else branch (same type)
-    auto appendList4 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList4 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value4(Compiler::StaticType::Number, 0);
     appendList4->workList = &list;
     appendList4->args.push_back({ Compiler::StaticType::Unknown, &value4 });
     instructionList.addInstruction(appendList4);
 
     // Inner if statement 2 end
-    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(innerEnd2);
 
     // Inner if statement 1 end
-    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(innerEnd1);
 
     // Outer if statement end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(outerEnd);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list, outerIf.get(), Compiler::StaticType::Number, false), Compiler::StaticType::Number);
@@ -1675,30 +1675,30 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, AppendToEmptyListInIfBranch)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // Append in if branch
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
     // Append after if statement - the list might not be empty anymore
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // Should return Unknown because the list might not be empty when the type changes
@@ -1711,33 +1711,33 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, AppendToEmptyListInElseBranch)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
     // Append in else branch
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
     // Append after if statement - the list might not be empty anymore
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // Should return Unknown because the list might not be empty when the type changes
@@ -1750,22 +1750,22 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_NewTypeAfterClear_Emp
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // Clear the list in the middle of the loop
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
     // Append after clear - this should set the new type
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // Should return String because the list was empty and append sets the type
@@ -1778,22 +1778,22 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_NewTypeAfterClear_Non
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // Clear the list in the middle of the loop
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
     // Append after clear - this should set the new type
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // Should return String because clear makes the list empty, then append sets the type
@@ -1806,29 +1806,29 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_MultipleAppendsAfterC
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // Clear the list
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
     // First append after clear
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Second append after clear (same type)
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 3.14);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // Should return Number because all appends after clear are the same type
@@ -1841,29 +1841,29 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_TypeConflictAfterClea
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // Clear the list
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
     // First append after clear
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Second append after clear (different type - creates conflict)
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // Should return Unknown because of type conflict after clear
@@ -1876,16 +1876,16 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_WithInsertAndReplace)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // Clear the list
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
     // Insert after clear
-    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, false);
     LLVMConstantRegister insertIndex(Compiler::StaticType::Number, 0);
     LLVMConstantRegister insertValue(Compiler::StaticType::Bool, true);
     insertList->workList = &list;
@@ -1894,7 +1894,7 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_WithInsertAndReplace)
     instructionList.addInstruction(insertList);
 
     // Replace after insert
-    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, false);
     LLVMConstantRegister replaceIndex(Compiler::StaticType::Number, 0);
     LLVMConstantRegister replaceValue(Compiler::StaticType::Bool, false);
     replaceList->workList = &list;
@@ -1902,7 +1902,7 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_WithInsertAndReplace)
     replaceList->args.push_back({ Compiler::StaticType::Unknown, &replaceValue });
     instructionList.addInstruction(replaceList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // Should return Bool because all operations after clear use Bool type
@@ -1915,40 +1915,40 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_ConditionalClear)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // If statement
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // Clear the list conditionally
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
     // Append after clear
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "cleared");
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Else branch
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
     // Append without clearing
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 42);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // Should return Unknown due to type conflict between branches
@@ -1961,30 +1961,30 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_AppendAfterClearingIn
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // If statement
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // Clear the list
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
     // End if statement
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
     // Append
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // Should return Unknown because the clearing branch might or might not run
@@ -1997,30 +1997,30 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_AppendAfterClearingIn
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // If statement
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // Clear the list
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
     // End if statement
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
     // Append
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 42);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // Should return Number because there are no type conflicts
@@ -2033,34 +2033,34 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_AppendAfterClearingIn
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // If statement
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // Else branch
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
     // Clear the list
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
     // End if statement
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
     // Append
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // Should return Unknown because the clearing branch might or might not run
@@ -2073,34 +2073,34 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_AppendAfterClearingIn
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // If statement
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // Else branch
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
     // Clear the list
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
     // End if statement
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
     // Append
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 42);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // Should return Number because there are no type conflicts
@@ -2113,34 +2113,34 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_MultipleClearsAndWrit
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // First clear
-    auto clearList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList1->workList = &list;
     instructionList.addInstruction(clearList1);
 
     // Append after first clear
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "first");
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Second clear
-    auto clearList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList2->workList = &list;
     instructionList.addInstruction(clearList2);
 
     // Append after second clear (different type)
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 42);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // Should return Number because the last clear+append sequence determines the final type
@@ -2153,15 +2153,15 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_ClearWithoutSubsequen
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // Clear the list but don't write anything after
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // Should return previous type since no writes occurred after clear
@@ -2174,28 +2174,28 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_ClearInNestedIf)
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // Nested if statement
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // Clear and write in nested if
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value(Compiler::StaticType::Bool, true);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &value });
     instructionList.addInstruction(appendList);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // Should return Unknown because the type-changing branch might or might not run
@@ -2208,35 +2208,35 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_AppendToEmptyListAndC
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // Append in if branch
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Clear the list in if branch
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
     // Append after if statement - should change type
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // Should return String because the list remains empty after the if statement
@@ -2249,35 +2249,35 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_AppendToEmptyListAndC
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // Append in if branch
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Bool, true);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Clear the list in if branch
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
     // Append after if statement - should change type
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // Should return String because the list remains empty after the if statement
@@ -2290,38 +2290,38 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_AppendToEmptyListAndC
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
     // Append in else branch
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Clear the list in else branch
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
     // Append after if statement - should change type
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // Should return String because the list remains empty after the if statement
@@ -2334,38 +2334,38 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, ClearListInLoop_AppendToEmptyListAndC
     LLVMInstructionList instructionList;
     List list("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
     // Append in else branch
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Bool, true);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Clear the list in else branch
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
     // Append after if statement - should change type
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(appendList2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // Should return String because the list remains empty after the if statement
@@ -2379,23 +2379,23 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CrossListDependency_ReadFromTypedList
     List sourceList("", "");
     List targetList("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // Clear sourceList
-    auto clear = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clear = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clear->workList = &sourceList;
     instructionList.addInstruction(clear);
 
     // Set sourceList type
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &sourceList;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Read from sourceList
-    auto getItem = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto getItem = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, false);
     LLVMConstantRegister index(Compiler::StaticType::Number, 0);
     getItem->workList = &sourceList;
     getItem->args.push_back({ Compiler::StaticType::Number, &index });
@@ -2406,12 +2406,12 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CrossListDependency_ReadFromTypedList
     instructionList.addInstruction(getItem);
 
     // Append the read value to targetList
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     appendList2->workList = &targetList;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, itemRegister.get() });
     instructionList.addInstruction(appendList2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // Target list type depends on source list type
@@ -2425,11 +2425,11 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CrossListDependency_ReadFromUnknownLi
     List sourceList("", "");
     List targetList("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // Read from sourceList
-    auto getItem = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto getItem = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, false);
     LLVMConstantRegister index(Compiler::StaticType::Number, 0);
     getItem->workList = &sourceList;
     getItem->args.push_back({ Compiler::StaticType::Number, &index });
@@ -2440,12 +2440,12 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CrossListDependency_ReadFromUnknownLi
     instructionList.addInstruction(getItem);
 
     // Append the read value to targetList
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     appendList->workList = &targetList;
     appendList->args.push_back({ Compiler::StaticType::Unknown, itemRegister.get() });
     instructionList.addInstruction(appendList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&targetList, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Unknown);
@@ -2459,28 +2459,28 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CrossListDependency_ChainedReads_Know
     List list2("", "");
     List list3("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // Clear list1
-    auto clear = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clear = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clear->workList = &list1;
     instructionList.addInstruction(clear);
 
     // Clear list2
-    clear = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    clear = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clear->workList = &list2;
     instructionList.addInstruction(clear);
 
     // Set list1 type
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     appendList1->workList = &list1;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(appendList1);
 
     // Read from list1
-    auto getItem1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto getItem1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, false);
     LLVMConstantRegister index1(Compiler::StaticType::Number, 0);
     getItem1->workList = &list1;
     getItem1->args.push_back({ Compiler::StaticType::Number, &index1 });
@@ -2491,13 +2491,13 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CrossListDependency_ChainedReads_Know
     instructionList.addInstruction(getItem1);
 
     // Append to list2
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     appendList2->workList = &list2;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, itemRegister1.get() });
     instructionList.addInstruction(appendList2);
 
     // Read from list2
-    auto getItem2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto getItem2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, false);
     LLVMConstantRegister index2(Compiler::StaticType::Number, 0);
     getItem2->workList = &list2;
     getItem2->args.push_back({ Compiler::StaticType::Number, &index2 });
@@ -2508,12 +2508,12 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CrossListDependency_ChainedReads_Know
     instructionList.addInstruction(getItem2);
 
     // Append to list3
-    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     appendList3->workList = &list3;
     appendList3->args.push_back({ Compiler::StaticType::Unknown, itemRegister2.get() });
     instructionList.addInstruction(appendList3);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     ASSERT_EQ(analyzer.listTypeAfterBranch(&list3, start.get(), Compiler::StaticType::Number, true), Compiler::StaticType::Number);
@@ -2527,11 +2527,11 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CrossListDependency_ChainedReads_Unkn
     List list2("", "");
     List list3("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // Read from list1
-    auto getItem1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto getItem1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, false);
     LLVMConstantRegister index1(Compiler::StaticType::Number, 0);
     getItem1->workList = &list1;
     getItem1->args.push_back({ Compiler::StaticType::Number, &index1 });
@@ -2542,13 +2542,13 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CrossListDependency_ChainedReads_Unkn
     instructionList.addInstruction(getItem1);
 
     // Append to list2
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     appendList2->workList = &list2;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, itemRegister1.get() });
     instructionList.addInstruction(appendList2);
 
     // Read from list2
-    auto getItem2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto getItem2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, false);
     LLVMConstantRegister index2(Compiler::StaticType::Number, 0);
     getItem2->workList = &list2;
     getItem2->args.push_back({ Compiler::StaticType::Number, &index2 });
@@ -2559,12 +2559,12 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CrossListDependency_ChainedReads_Unkn
     instructionList.addInstruction(getItem2);
 
     // Append to list3
-    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     appendList3->workList = &list3;
     appendList3->args.push_back({ Compiler::StaticType::Unknown, itemRegister2.get() });
     instructionList.addInstruction(appendList3);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // list3 should have Unknown type due to chained cross-list dependencies
@@ -2578,15 +2578,15 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CrossListDependency_ConditionalRead)
     List sourceList("", "");
     List targetList("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // If statement
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // Read from sourceList in if branch
-    auto getItem = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto getItem = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, false);
     LLVMConstantRegister index(Compiler::StaticType::Number, 0);
     getItem->workList = &sourceList;
     getItem->args.push_back({ Compiler::StaticType::Number, &index });
@@ -2597,26 +2597,26 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CrossListDependency_ConditionalRead)
     instructionList.addInstruction(getItem);
 
     // Append to targetList
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     appendList->workList = &targetList;
     appendList->args.push_back({ Compiler::StaticType::Unknown, itemRegister.get() });
     instructionList.addInstruction(appendList);
 
     // Else branch
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
     // Direct append of constant value
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister directValue(Compiler::StaticType::Number, 42);
     appendList2->workList = &targetList;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &directValue });
     instructionList.addInstruction(appendList2);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // Should return Unknown due to cross-list dependency and conditional execution
@@ -2630,11 +2630,11 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CrossListDependency_ReadWithInsertAnd
     List sourceList("", "");
     List targetList("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(start);
 
     // Read from sourceList
-    auto getItem = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto getItem = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, false);
     LLVMConstantRegister index(Compiler::StaticType::Number, 0);
     getItem->workList = &sourceList;
     getItem->args.push_back({ Compiler::StaticType::Number, &index });
@@ -2645,7 +2645,7 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CrossListDependency_ReadWithInsertAnd
     instructionList.addInstruction(getItem);
 
     // Insert the read value to targetList
-    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, nullptr, false);
+    auto insertList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::InsertToList, false);
     LLVMConstantRegister insertIndex(Compiler::StaticType::Number, 0);
     insertList->workList = &targetList;
     insertList->args.push_back({ Compiler::StaticType::Number, &insertIndex });
@@ -2653,7 +2653,7 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CrossListDependency_ReadWithInsertAnd
     instructionList.addInstruction(insertList);
 
     // Replace with another read from the same list
-    auto getItem2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto getItem2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, false);
     LLVMConstantRegister index2(Compiler::StaticType::Number, 1);
     getItem2->workList = &sourceList;
     getItem2->args.push_back({ Compiler::StaticType::Number, &index2 });
@@ -2663,14 +2663,14 @@ TEST(LLVMTypeAnalyzer_ListTypeAfterBranch, CrossListDependency_ReadWithInsertAnd
     getItem2->functionReturnReg = itemRegister2.get();
     instructionList.addInstruction(getItem2);
 
-    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, nullptr, false);
+    auto replaceList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ListReplace, false);
     LLVMConstantRegister replaceIndex(Compiler::StaticType::Number, 0);
     replaceList->workList = &targetList;
     replaceList->args.push_back({ Compiler::StaticType::Number, &replaceIndex });
     replaceList->args.push_back({ Compiler::StaticType::Unknown, itemRegister2.get() });
     instructionList.addInstruction(replaceList);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(end);
 
     // Should have Unknown type due to cross-list dependencies
diff --git a/test/llvm/type_analyzer/mixed_test.cpp b/test/llvm/type_analyzer/mixed_test.cpp
index 9ef3fc95..7d7af430 100644
--- a/test/llvm/type_analyzer/mixed_test.cpp
+++ b/test/llvm/type_analyzer/mixed_test.cpp
@@ -15,31 +15,31 @@ TEST(LLVMTypeAnalyzer_MixedTest, VariableToList_SimpleTransfer_NonEmpty)
     Variable sourceVar("sourceVar", "");
     List targetList("targetList", "");
 
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &targetList;
     instructionList.addInstruction(clearList);
 
     // Write to variable
-    auto writeVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto writeVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister varValue(Compiler::StaticType::String, "hello");
     writeVar->workVariable = &sourceVar;
     writeVar->args.push_back({ Compiler::StaticType::Unknown, &varValue });
     instructionList.addInstruction(writeVar);
 
     // Read from variable and write to list
-    auto readVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     auto readVarReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
     readVar->functionReturnReg = readVarReg.get();
     readVarReg->instruction = readVar;
     readVar->workVariable = &sourceVar;
     instructionList.addInstruction(readVar);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     appendList->workList = &targetList;
     appendList->args.push_back({ Compiler::StaticType::Unknown, readVarReg.get() });
     instructionList.addInstruction(appendList);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // List type should match variable type
@@ -53,19 +53,19 @@ TEST(LLVMTypeAnalyzer_MixedTest, ListToVariable_SimpleTransfer_Empty)
     List sourceList("sourceList", "");
     Variable targetVar("targetVar", "");
 
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &sourceList;
     instructionList.addInstruction(clearList);
 
     // Write to list
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister listValue(Compiler::StaticType::Bool, true);
     appendList->workList = &sourceList;
     appendList->args.push_back({ Compiler::StaticType::Unknown, &listValue });
     instructionList.addInstruction(appendList);
 
     // Read from list and write to variable
-    auto readList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, false);
     auto readListReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
     readList->functionReturnReg = readListReg.get();
     readListReg->instruction = readList;
@@ -74,12 +74,12 @@ TEST(LLVMTypeAnalyzer_MixedTest, ListToVariable_SimpleTransfer_Empty)
     readList->args.push_back({ Compiler::StaticType::Number, &index });
     instructionList.addInstruction(readList);
 
-    auto writeVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto writeVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     writeVar->workVariable = &targetVar;
     writeVar->args.push_back({ Compiler::StaticType::Unknown, readListReg.get() });
     instructionList.addInstruction(writeVar);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Variable type should match list type
@@ -94,31 +94,31 @@ TEST(LLVMTypeAnalyzer_MixedTest, CircularVarListDependency_TypeSafety)
     List list("list", "");
 
     // Initialize variable with number
-    auto writeVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto writeVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
     writeVar1->workVariable = &var;
     writeVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(writeVar1);
 
     // Read from variable and write to list
-    auto readVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     auto readVarReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
     readVar->functionReturnReg = readVarReg.get();
     readVarReg->instruction = readVar;
     readVar->workVariable = &var;
     instructionList.addInstruction(readVar);
 
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, readVarReg.get() });
     instructionList.addInstruction(appendList);
 
     // Read from list and write back to variable (circular dependency)
-    auto readList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, false);
     auto readListReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
     readList->functionReturnReg = readListReg.get();
     readListReg->instruction = readList;
@@ -127,12 +127,12 @@ TEST(LLVMTypeAnalyzer_MixedTest, CircularVarListDependency_TypeSafety)
     readList->args.push_back({ Compiler::StaticType::Number, &index });
     instructionList.addInstruction(readList);
 
-    auto writeVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto writeVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     writeVar2->workVariable = &var;
     writeVar2->args.push_back({ Compiler::StaticType::Unknown, readListReg.get() });
     instructionList.addInstruction(writeVar2);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should handle circular dependency gracefully
@@ -147,44 +147,44 @@ TEST(LLVMTypeAnalyzer_MixedTest, LoopWithVarListInteraction_TypeConflict)
     Variable var("var", "");
     List list("list", "");
 
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
     // First iteration: write string to variable
-    auto writeVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto writeVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "text");
     writeVar1->workVariable = &var;
     writeVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(writeVar1);
 
-    auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(loopStart);
 
     // Read from variable and write to list
-    auto readVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     auto readVarReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
     readVar->functionReturnReg = readVarReg.get();
     readVarReg->instruction = readVar;
     readVar->workVariable = &var;
     instructionList.addInstruction(readVar);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, readVarReg.get() });
     instructionList.addInstruction(appendList);
 
     // Second iteration: write number to variable (creates type conflict)
-    auto writeVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto writeVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 42);
     writeVar2->workVariable = &var;
     writeVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(writeVar2);
 
-    auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(loopEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should return Unknown due to type conflict
@@ -198,58 +198,58 @@ TEST(LLVMTypeAnalyzer_MixedTest, ConditionalVarListTransfer_TypeConflict)
     Variable var("var", "");
     List list("list", "");
 
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     instructionList.addInstruction(ifStart);
 
     // If branch: write number to variable, transfer to list
-    auto writeVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto writeVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 123);
     writeVar1->workVariable = &var;
     writeVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(writeVar1);
 
-    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     auto readVar1Reg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
     readVar1->functionReturnReg = readVar1Reg.get();
     readVar1Reg->instruction = readVar1;
     readVar1->workVariable = &var;
     instructionList.addInstruction(readVar1);
 
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, readVar1Reg.get() });
     instructionList.addInstruction(appendList1);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     instructionList.addInstruction(elseStart);
 
     // Else branch: write string to variable, transfer to list
-    auto writeVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto writeVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "hello");
     writeVar2->workVariable = &var;
     writeVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(writeVar2);
 
-    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     auto readVar2Reg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
     readVar2->functionReturnReg = readVar2Reg.get();
     readVar2Reg->instruction = readVar2;
     readVar2->workVariable = &var;
     instructionList.addInstruction(readVar2);
 
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, readVar2Reg.get() });
     instructionList.addInstruction(appendList2);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     instructionList.addInstruction(ifEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should return Unknown due to conditional type conflicts
@@ -264,51 +264,51 @@ TEST(LLVMTypeAnalyzer_MixedTest, MultipleVarsToSingleList_TypePropagation)
     Variable var2("var2", "");
     List list("list", "");
 
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
     // Initialize first variable with boolean
-    auto writeVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto writeVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Bool, true);
     writeVar1->workVariable = &var1;
     writeVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(writeVar1);
 
     // Initialize second variable with same type
-    auto writeVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto writeVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Bool, false);
     writeVar2->workVariable = &var2;
     writeVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(writeVar2);
 
     // Read from first variable and write to list
-    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     auto readVar1Reg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
     readVar1->functionReturnReg = readVar1Reg.get();
     readVar1Reg->instruction = readVar1;
     readVar1->workVariable = &var1;
     instructionList.addInstruction(readVar1);
 
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     appendList1->workList = &list;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, readVar1Reg.get() });
     instructionList.addInstruction(appendList1);
 
     // Read from second variable and write to list
-    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     auto readVar2Reg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
     readVar2->functionReturnReg = readVar2Reg.get();
     readVar2Reg->instruction = readVar2;
     readVar2->workVariable = &var2;
     instructionList.addInstruction(readVar2);
 
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     appendList2->workList = &list;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, readVar2Reg.get() });
     instructionList.addInstruction(appendList2);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // List should have Bool type from both variables
@@ -323,25 +323,25 @@ TEST(LLVMTypeAnalyzer_MixedTest, SingleListToMultipleVars_TypePropagation)
     Variable var1("var1", "");
     Variable var2("var2", "");
 
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &sourceList;
     instructionList.addInstruction(clearList);
 
     // Initialize list with string values
-    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister listValue1(Compiler::StaticType::String, "first");
     appendList1->workList = &sourceList;
     appendList1->args.push_back({ Compiler::StaticType::Unknown, &listValue1 });
     instructionList.addInstruction(appendList1);
 
-    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     LLVMConstantRegister listValue2(Compiler::StaticType::String, "second");
     appendList2->workList = &sourceList;
     appendList2->args.push_back({ Compiler::StaticType::Unknown, &listValue2 });
     instructionList.addInstruction(appendList2);
 
     // Read first item and write to first variable
-    auto readList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readList1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, false);
     auto readList1Reg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
     readList1->functionReturnReg = readList1Reg.get();
     readList1Reg->instruction = readList1;
@@ -350,13 +350,13 @@ TEST(LLVMTypeAnalyzer_MixedTest, SingleListToMultipleVars_TypePropagation)
     readList1->args.push_back({ Compiler::StaticType::Number, &index1 });
     instructionList.addInstruction(readList1);
 
-    auto writeVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto writeVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     writeVar1->workVariable = &var1;
     writeVar1->args.push_back({ Compiler::StaticType::Unknown, readList1Reg.get() });
     instructionList.addInstruction(writeVar1);
 
     // Read second item and write to second variable
-    auto readList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readList2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, false);
     auto readList2Reg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
     readList2->functionReturnReg = readList2Reg.get();
     readList2Reg->instruction = readList2;
@@ -365,12 +365,12 @@ TEST(LLVMTypeAnalyzer_MixedTest, SingleListToMultipleVars_TypePropagation)
     readList2->args.push_back({ Compiler::StaticType::Number, &index2 });
     instructionList.addInstruction(readList2);
 
-    auto writeVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto writeVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     writeVar2->workVariable = &var2;
     writeVar2->args.push_back({ Compiler::StaticType::Unknown, readList2Reg.get() });
     instructionList.addInstruction(writeVar2);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Both variables should have String type from the list
@@ -386,32 +386,32 @@ TEST(LLVMTypeAnalyzer_MixedTest, ComplexChain_VarToListToVar_TypePropagation)
     List intermediateList("intermediateList", "");
     Variable targetVar("targetVar", "");
 
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &intermediateList;
     instructionList.addInstruction(clearList);
 
     // Initialize source variable
-    auto writeSourceVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto writeSourceVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister sourceValue(Compiler::StaticType::Number, 3.14159);
     writeSourceVar->workVariable = &sourceVar;
     writeSourceVar->args.push_back({ Compiler::StaticType::Unknown, &sourceValue });
     instructionList.addInstruction(writeSourceVar);
 
     // Read from source variable and write to intermediate list
-    auto readSourceVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readSourceVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     auto readSourceVarReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
     readSourceVar->functionReturnReg = readSourceVarReg.get();
     readSourceVarReg->instruction = readSourceVar;
     readSourceVar->workVariable = &sourceVar;
     instructionList.addInstruction(readSourceVar);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     appendList->workList = &intermediateList;
     appendList->args.push_back({ Compiler::StaticType::Unknown, readSourceVarReg.get() });
     instructionList.addInstruction(appendList);
 
     // Read from intermediate list and write to target variable
-    auto readList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, nullptr, false);
+    auto readList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, false);
     auto readListReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
     readList->functionReturnReg = readListReg.get();
     readListReg->instruction = readList;
@@ -420,12 +420,12 @@ TEST(LLVMTypeAnalyzer_MixedTest, ComplexChain_VarToListToVar_TypePropagation)
     readList->args.push_back({ Compiler::StaticType::Number, &index });
     instructionList.addInstruction(readList);
 
-    auto writeTargetVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto writeTargetVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     writeTargetVar->workVariable = &targetVar;
     writeTargetVar->args.push_back({ Compiler::StaticType::Unknown, readListReg.get() });
     instructionList.addInstruction(writeTargetVar);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Type should propagate through the chain: sourceVar -> intermediateList -> targetVar
@@ -440,50 +440,50 @@ TEST(LLVMTypeAnalyzer_MixedTest, NestedLoopWithMixedDependencies_TypeConflict)
     Variable var("var", "");
     List list("list", "");
 
-    auto outerLoopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto outerLoopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(outerLoopStart);
 
     // Write to variable in outer loop
-    auto writeVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto writeVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Bool, true);
     writeVar1->workVariable = &var;
     writeVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     instructionList.addInstruction(writeVar1);
 
-    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, nullptr, false);
+    auto clearList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ClearList, false);
     clearList->workList = &list;
     instructionList.addInstruction(clearList);
 
-    auto innerLoopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     instructionList.addInstruction(innerLoopStart);
 
     // Read from variable and write to list in inner loop
-    auto readVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     auto readVarReg = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
     readVar->functionReturnReg = readVarReg.get();
     readVarReg->instruction = readVar;
     readVar->workVariable = &var;
     instructionList.addInstruction(readVar);
 
-    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, nullptr, false);
+    auto appendList = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::AppendToList, false);
     appendList->workList = &list;
     appendList->args.push_back({ Compiler::StaticType::Unknown, readVarReg.get() });
     instructionList.addInstruction(appendList);
 
     // Write different type to variable in inner loop (creates conflict)
-    auto writeVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto writeVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "conflict");
     writeVar2->workVariable = &var;
     writeVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     instructionList.addInstruction(writeVar2);
 
-    auto innerLoopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerLoopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(innerLoopEnd);
 
-    auto outerLoopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerLoopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     instructionList.addInstruction(outerLoopEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     instructionList.addInstruction(funcCall);
 
     // Should return Unknown due to type conflicts in nested loops
diff --git a/test/llvm/type_analyzer/variabletype_test.cpp b/test/llvm/type_analyzer/variabletype_test.cpp
index ea7090e8..63256c9d 100644
--- a/test/llvm/type_analyzer/variabletype_test.cpp
+++ b/test/llvm/type_analyzer/variabletype_test.cpp
@@ -18,7 +18,7 @@ TEST(LLVMTypeAnalyzer_VariableType, NullVariable)
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.variableType(nullptr, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
@@ -37,7 +37,7 @@ TEST(LLVMTypeAnalyzer_VariableType, NoWriteOperationsKnownType)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
@@ -49,7 +49,7 @@ TEST(LLVMTypeAnalyzer_VariableType, NoWriteOperationsUnknownType)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown);
@@ -61,7 +61,7 @@ TEST(LLVMTypeAnalyzer_VariableType, QueryPointIsWrite)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 1.25);
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
@@ -76,19 +76,19 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeNumber_Before)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 1.25);
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
@@ -100,19 +100,19 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeNumber_After)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 1.25);
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
@@ -124,19 +124,19 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeBool_Before)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::Bool, true);
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Bool);
@@ -148,19 +148,19 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeBool_After)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::Bool, true);
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Bool);
@@ -172,19 +172,19 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeString_Before)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::String);
@@ -196,19 +196,19 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteSameTypeString_After)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::String);
@@ -220,19 +220,19 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteStringOptimization)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "1.25");
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     // Although string is assigned, it's constant and represents a number
@@ -246,27 +246,27 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteMultipleVariables)
     Variable var1("", "");
     Variable var2("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
     // Set var1
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 6);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Set var2
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     setVar2->workVariable = &var2;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableType(&var1, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
@@ -278,19 +278,19 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteFromUnknownType_Before)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMRegister value(Compiler::StaticType::Unknown);
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
@@ -302,19 +302,19 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteFromUnknownType_After)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMRegister value(Compiler::StaticType::Unknown);
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
@@ -326,19 +326,19 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteToUnknownType_Before)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 5);
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     // The type is known because a number is assigned before the point
@@ -351,19 +351,19 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteToUnknownType_After)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 5);
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     // The type is not known because a number is assigned after the point
@@ -376,19 +376,19 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteUnknownToUnknownType_Before)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMRegister value(Compiler::StaticType::Unknown);
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown);
@@ -400,19 +400,19 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteUnknownToUnknownType_After)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMRegister value(Compiler::StaticType::Unknown);
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown);
@@ -424,19 +424,19 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeNumberToString_
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
@@ -448,19 +448,19 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeNumberToString_
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
@@ -472,19 +472,19 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeStringToNumber_
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 5.8);
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Unknown);
@@ -496,19 +496,19 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeNumberToBool_Af
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::Bool, true);
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
@@ -520,19 +520,19 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeBoolToNumber_Be
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 1);
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number);
@@ -544,19 +544,19 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeBoolToNumber_Af
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 1);
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Unknown);
@@ -568,19 +568,19 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeBoolToString_Af
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "abc");
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Bool), Compiler::StaticType::Unknown);
@@ -592,19 +592,19 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeStringToBool_Be
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::Bool, false);
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Bool);
@@ -616,19 +616,19 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentTypeStringToBool_Af
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::Bool, false);
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Unknown);
@@ -640,25 +640,25 @@ TEST(LLVMTypeAnalyzer_VariableType, Loop_SingleWriteDifferentType_BeforeAndAfter
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "test");
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Bool, true);
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
@@ -670,19 +670,19 @@ TEST(LLVMTypeAnalyzer_VariableType, IfStatement_SingleWriteDifferentType_Before)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(start);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
@@ -694,19 +694,19 @@ TEST(LLVMTypeAnalyzer_VariableType, IfStatement_SingleWriteDifferentType_After_I
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(start);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(end);
 
     // Since this isn't a loop, the write after the point doesn't affect the type
@@ -719,22 +719,22 @@ TEST(LLVMTypeAnalyzer_VariableType, IfStatement_SingleWriteDifferentType_After_E
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(start);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     list.addInstruction(elseStart);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(end);
 
     // Since this isn't a loop, the write after the point doesn't affect the type
@@ -747,19 +747,19 @@ TEST(LLVMTypeAnalyzer_VariableType, WriteSameTypeInLoop)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 1.25);
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
@@ -771,19 +771,19 @@ TEST(LLVMTypeAnalyzer_VariableType, WriteDifferentTypeInLoop)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     // Type is not known because the loop might not run at all
@@ -796,25 +796,25 @@ TEST(LLVMTypeAnalyzer_VariableType, OverrideDifferentTypeBeforeLoop)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 1.25);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25);
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Number);
@@ -826,25 +826,25 @@ TEST(LLVMTypeAnalyzer_VariableType, OverrideUnknownTypeBeforeLoop)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 1.25);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25);
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Number);
@@ -856,19 +856,19 @@ TEST(LLVMTypeAnalyzer_VariableType, WriteSameTypeInIfStatement)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(start);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 1.25);
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
@@ -880,19 +880,19 @@ TEST(LLVMTypeAnalyzer_VariableType, WriteDifferentTypeInIfStatement)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(start);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 5.8);
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     // Type is not known because the if statement might not run at all
@@ -905,34 +905,34 @@ TEST(LLVMTypeAnalyzer_VariableType, OverrideDifferentTypeBeforeIfElseStatement)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 1.25);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(start);
 
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25);
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     list.addInstruction(elseStart);
 
-    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value3(Compiler::StaticType::Number, 2.5);
     setVar3->workVariable = &var;
     setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     list.addInstruction(setVar3);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::String), Compiler::StaticType::Number);
@@ -944,34 +944,34 @@ TEST(LLVMTypeAnalyzer_VariableType, OverrideUnknownTypeBeforeIfElseStatement)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 1.25);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(start);
 
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25);
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     list.addInstruction(elseStart);
 
-    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value3(Compiler::StaticType::Number, 2.5);
     setVar3->workVariable = &var;
     setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     list.addInstruction(setVar3);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(end);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Number);
@@ -984,20 +984,20 @@ TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesSameTypeNumber)
     Variable var("", "");
 
     // First write: string "abc" (incompatible with Number)
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "abc");
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Second write: number 5.25 (compatible with Number pre-loop type)
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 5.25);
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     // Should return Number type because final assignment writes a number
@@ -1011,20 +1011,20 @@ TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesSameTypeString)
     Variable var("", "");
 
     // First write: number 42 (incompatible with String)
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Second write: string "hello" (compatible with String pre-loop type)
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "hello");
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     // Should return String type because final assignment writes a string
@@ -1038,20 +1038,20 @@ TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesSameTypeUnknown)
     Variable var("", "");
 
     // First write: unknown type
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMRegister value1(Compiler::StaticType::Unknown);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Second write: string "hello" (compatible with String pre-loop type)
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "hello");
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     // Should return String type because final assignment writes a string
@@ -1065,20 +1065,20 @@ TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesWithStringOptimization)
     Variable var("", "");
 
     // First write: string "abc" (incompatible with Number)
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "abc");
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Second write: string "3.14" (optimized to Number, compatible with pre-loop type)
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "3.14");
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     // Should return Number type because final assignment writes a string which is optimized to Number type
@@ -1092,20 +1092,20 @@ TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesNumberToString)
     Variable var("", "");
 
     // First write: number 42 (compatible with Number)
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Second write: string "hello" (incompatible with Number pre-loop type)
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "hello");
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     // Should return String type because final assignment writes a string
@@ -1118,13 +1118,13 @@ TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesBoolToNumber)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 42.5);
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     // Should return Number type because final assignment writes a number
@@ -1137,13 +1137,13 @@ TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesBoolToString)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "hello");
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     // Should return String type because final assignment writes a string
@@ -1156,13 +1156,13 @@ TEST(LLVMTypeAnalyzer_VariableType, MultipleWritesBoolToStringNumberOptimization
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "3.14");
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     // String "3.14" gets optimized to Number, which is still different from Bool
@@ -1175,30 +1175,30 @@ TEST(LLVMTypeAnalyzer_VariableType, TypeChangeInIfBranch)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(ifStart);
 
     // First write - changes type
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "test");
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     list.addInstruction(elseStart);
 
     // Second write - does not change type
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 42);
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(ifEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     // Returns unknown type because both branches might run
@@ -1211,30 +1211,30 @@ TEST(LLVMTypeAnalyzer_VariableType, TypeChangeInElseBranch)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(ifStart);
 
     // First write - does not change type
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     list.addInstruction(elseStart);
 
     // Second write - changes type
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(ifEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     // Returns unknown type because both branches might run
@@ -1247,30 +1247,30 @@ TEST(LLVMTypeAnalyzer_VariableType, IfElseWithEqualTypes_SameType)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(ifStart);
 
     // First write - does not change type
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     list.addInstruction(elseStart);
 
     // Second write - does not change type
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25);
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(ifEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
@@ -1282,30 +1282,30 @@ TEST(LLVMTypeAnalyzer_VariableType, IfElseWithEqualTypes_DifferentTypes)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(ifStart);
 
     // First write - changes type to string
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "Lorem");
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     list.addInstruction(elseStart);
 
     // Second write - changes type to string
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "ipsum");
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(ifEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
@@ -1317,33 +1317,33 @@ TEST(LLVMTypeAnalyzer_VariableType, IfStatementAfterLoop_SameTypes)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(loopStart);
 
     // First write - does not change type
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
-    auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(loopEnd);
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(ifStart);
 
     // Second write - does not change type
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 2);
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(ifEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
@@ -1355,33 +1355,33 @@ TEST(LLVMTypeAnalyzer_VariableType, IfStatementAfterLoop_DifferentTypes)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto loopStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(loopStart);
 
     // First write - does not change type
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
-    auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto loopEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(loopEnd);
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(ifStart);
 
     // Second write - changes type
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(ifEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
@@ -1393,46 +1393,46 @@ TEST(LLVMTypeAnalyzer_VariableType, TwoIfStatements_DifferentTypes)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(ifStart);
 
     // First write - does not change type
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     list.addInstruction(elseStart);
 
     // Second write - does not change type
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 4);
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(ifEnd);
 
-    ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(ifStart);
 
-    elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     list.addInstruction(elseStart);
 
     // Third write - changes type (in else branch)
-    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value3(Compiler::StaticType::String, "test");
     setVar3->workVariable = &var;
     setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     list.addInstruction(setVar3);
 
-    ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(ifEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
@@ -1445,36 +1445,36 @@ TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithTypeChange_Before)
     Variable var("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(outerLoop);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     // Variable write inside outer loop
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Inner loop begin
-    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(innerLoop);
 
     // Variable write inside inner loop
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
     // Inner loop end
-    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(innerEnd);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(outerEnd);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
@@ -1487,36 +1487,36 @@ TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithTypeChange_BeforeInner)
     Variable var("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(outerLoop);
 
     // Variable write inside outer loop
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     // Inner loop begin
-    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(innerLoop);
 
     // Variable write inside inner loop
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
     // Inner loop end
-    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(innerEnd);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(outerEnd);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
@@ -1529,36 +1529,36 @@ TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithTypeChange_AfterWriteInsideInn
     Variable var("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(outerLoop);
 
     // Variable write inside outer loop
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Inner loop begin
-    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(innerLoop);
 
     // Variable write inside inner loop
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     // Inner loop end
-    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(innerEnd);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(outerEnd);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
@@ -1571,36 +1571,36 @@ TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithTypeChange_After)
     Variable var("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(outerLoop);
 
     // Variable write inside outer loop
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Inner loop begin
-    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(innerLoop);
 
     // Variable write inside inner loop
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
     // Inner loop end
-    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(innerEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(outerEnd);
 
     // Type is not known because the inner loop might not run at all
@@ -1614,36 +1614,36 @@ TEST(LLVMTypeAnalyzer_VariableType, NestedLoopWithoutTypeChange)
     Variable var("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginWhileLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginWhileLoop, false);
     list.addInstruction(outerLoop);
 
     // Variable write inside outer loop
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Inner loop begin
-    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(innerLoop);
 
     // Variable write inside inner loop
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 2.5);
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
     // Inner loop end
-    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(innerEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(outerEnd);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
@@ -1656,43 +1656,43 @@ TEST(LLVMTypeAnalyzer_VariableType, NestedLoopTypeChangesButResets)
     Variable var("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(outerLoop);
 
     // Variable write inside outer loop
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Inner loop begin
-    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false);
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, false);
     list.addInstruction(innerLoop);
 
     // Variable write inside inner loop
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
     // Inner loop end
-    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(innerEnd);
 
     // Variable write after inner loop - resets type
-    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value3(Compiler::StaticType::Number, 2);
     setVar3->workVariable = &var;
     setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     list.addInstruction(setVar3);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(outerEnd);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
@@ -1705,43 +1705,43 @@ TEST(LLVMTypeAnalyzer_VariableType, NestedLoopTypeChangesAndDoesNotReset)
     Variable var("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(outerLoop);
 
     // Variable write inside outer loop
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Inner loop begin
-    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginWhileLoop, nullptr, false);
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginWhileLoop, false);
     list.addInstruction(innerLoop);
 
     // Variable write inside inner loop
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
     // Inner loop end
-    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(innerEnd);
 
     // Variable write after inner loop - keeps the different type
-    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value3(Compiler::StaticType::String, "abc");
     setVar3->workVariable = &var;
     setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     list.addInstruction(setVar3);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(outerEnd);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
@@ -1754,51 +1754,51 @@ TEST(LLVMTypeAnalyzer_VariableType, MultipleNestedLoopsWithTypeChange)
     Variable var("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(outerLoop);
 
     // Variable write inside outer loop
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Inner loop 1 begin
-    auto innerLoop1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(innerLoop1);
 
     // Variable write inside inner loop 1
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75);
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
     // Inner loop 2 begin
-    auto innerLoop2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(innerLoop2);
 
     // Variable write inside inner loop 2
-    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value3(Compiler::StaticType::String, "abc");
     setVar3->workVariable = &var;
     setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     list.addInstruction(setVar3);
 
     // Inner loop 2 end
-    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(innerEnd2);
 
     // Inner loop 1 end
-    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(innerEnd1);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(outerEnd);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
@@ -1811,51 +1811,51 @@ TEST(LLVMTypeAnalyzer_VariableType, MultipleNestedLoopsWithTypeChangeButTypeRese
     Variable var("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(outerLoop);
 
     // Variable write inside outer loop
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Inner loop 1 begin
-    auto innerLoop1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(innerLoop1);
 
     // Inner loop 2 begin
-    auto innerLoop2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(innerLoop2);
 
     // Variable write inside inner loop 2
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "abc");
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
     // Inner loop 2 end
-    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(innerEnd2);
 
     // Variable write inside inner loop 1 - resets type
-    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value3(Compiler::StaticType::Number, 2.75);
     setVar3->workVariable = &var;
     setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     list.addInstruction(setVar3);
 
     // Inner loop 1 end
-    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(innerEnd1);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(outerEnd);
 
     ASSERT_EQ(analyzer.variableType(&var, funcCall.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
@@ -1868,40 +1868,40 @@ TEST(LLVMTypeAnalyzer_VariableType, SameTypeIfElseInLoopWithTypeChange)
     Variable var("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(outerLoop);
 
     // Inner if statement begin
-    auto innerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto innerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(innerIf);
 
     // Variable write inside inner if statement if branch
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "abc");
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Inner if statement else branch
-    auto innerElse = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto innerElse = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     list.addInstruction(innerElse);
 
     // Variable write inside inner if statement else branch
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "def");
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
     // Inner if statement end
-    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(innerEnd);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(outerEnd);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
     // The type always changes to string
@@ -1915,14 +1915,14 @@ TEST(LLVMTypeAnalyzer_VariableType, CrossVariableDependency_SimpleAssignment)
     Variable var1("", ""), var2("", "");
 
     // First write: var2 = "test" (String type)
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "test");
     setVar2->workVariable = &var2;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar2);
 
     // Second write: var1 = var2 (cross-variable dependency)
-    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     list.addInstruction(readVar2);
     readVar2->workVariable = &var2;
 
@@ -1931,13 +1931,13 @@ TEST(LLVMTypeAnalyzer_VariableType, CrossVariableDependency_SimpleAssignment)
     var2Value.instruction = readVar2;
     readVar2->functionReturnReg = &var2Value;
 
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value });
     list.addInstruction(setVar1);
 
     // Query position after the assignment
-    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(queryPos);
 
     // var1 should have String type due to cross-variable dependency
@@ -1951,14 +1951,14 @@ TEST(LLVMTypeAnalyzer_VariableType, CrossVariableDependency_TypeMismatch)
     Variable var1("", ""), var2("", "");
 
     // First write: var2 = "test" (String type)
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "test");
     setVar2->workVariable = &var2;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar2);
 
     // Second write: var1 = var2 (cross-variable dependency with type mismatch)
-    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     list.addInstruction(readVar2);
     readVar2->workVariable = &var2;
 
@@ -1967,13 +1967,13 @@ TEST(LLVMTypeAnalyzer_VariableType, CrossVariableDependency_TypeMismatch)
     var2Value.instruction = readVar2;
     readVar2->functionReturnReg = &var2Value;
 
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value });
     list.addInstruction(setVar1);
 
     // Query position after the assignment
-    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(queryPos);
 
     // var1 should have String type (different from Number previousType)
@@ -1987,18 +1987,18 @@ TEST(LLVMTypeAnalyzer_VariableType, CrossVariableDependency_QueryBeforeAssignmen
     Variable var1("", ""), var2("", "");
 
     // Query position before any assignments
-    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(queryPos);
 
     // First write: var2 = "test" (String type) - after query position
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "test");
     setVar2->workVariable = &var2;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar2);
 
     // Second write: var1 = var2 (cross-variable dependency) - after query position
-    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     list.addInstruction(readVar2);
     readVar2->workVariable = &var2;
 
@@ -2007,7 +2007,7 @@ TEST(LLVMTypeAnalyzer_VariableType, CrossVariableDependency_QueryBeforeAssignmen
     var2Value.instruction = readVar2;
     readVar2->functionReturnReg = &var2Value;
 
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value });
     list.addInstruction(setVar1);
@@ -2023,14 +2023,14 @@ TEST(LLVMTypeAnalyzer_VariableType, CrossVariableDependency_ChainedAssignments)
     Variable var1("", ""), var2("", ""), var3("", "");
 
     // First write: var3 = 42 (Number type)
-    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
     setVar3->workVariable = &var3;
     setVar3->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar3);
 
     // Second write: var2 = var3 (cross-variable dependency)
-    auto readVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     list.addInstruction(readVar3);
     readVar3->workVariable = &var3;
 
@@ -2039,13 +2039,13 @@ TEST(LLVMTypeAnalyzer_VariableType, CrossVariableDependency_ChainedAssignments)
     var3Value.instruction = readVar3;
     readVar3->functionReturnReg = &var3Value;
 
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar2->workVariable = &var2;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &var3Value });
     list.addInstruction(setVar2);
 
     // Third write: var1 = var2 (chained cross-variable dependency)
-    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     list.addInstruction(readVar2);
     readVar2->workVariable = &var2;
 
@@ -2054,13 +2054,13 @@ TEST(LLVMTypeAnalyzer_VariableType, CrossVariableDependency_ChainedAssignments)
     var2Value.instruction = readVar2;
     readVar2->functionReturnReg = &var2Value;
 
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value });
     list.addInstruction(setVar1);
 
     // Query position after all assignments
-    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(queryPos);
 
     // var1 should have Number type through the chain var1 = var2 = var3 = 42
@@ -2074,7 +2074,7 @@ TEST(LLVMTypeAnalyzer_VariableType, CrossVariableDependency_CircularReference)
     Variable var1("", ""), var2("", "");
 
     // First write: var1 = var2 (circular dependency setup)
-    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     list.addInstruction(readVar2);
     readVar2->workVariable = &var2;
 
@@ -2083,13 +2083,13 @@ TEST(LLVMTypeAnalyzer_VariableType, CrossVariableDependency_CircularReference)
     var2Value.instruction = readVar2;
     readVar2->functionReturnReg = &var2Value;
 
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value });
     list.addInstruction(setVar1);
 
     // Second write: var2 = var1 (completes circular dependency)
-    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     list.addInstruction(readVar1);
     readVar1->workVariable = &var1;
 
@@ -2098,13 +2098,13 @@ TEST(LLVMTypeAnalyzer_VariableType, CrossVariableDependency_CircularReference)
     var1Value.instruction = readVar1;
     readVar1->functionReturnReg = &var1Value;
 
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar2->workVariable = &var2;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &var1Value });
     list.addInstruction(setVar2);
 
     // Query position after circular assignments
-    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(queryPos);
 
     // Should return Unknown due to circular dependency
@@ -2117,18 +2117,18 @@ TEST(LLVMTypeAnalyzer_VariableType, CrossVariableDependency_InIfStatement_QueryI
     LLVMInstructionList list;
     Variable var1("", ""), var2("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(start);
 
     // First write: var2 = 3.14 (Number type)
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 3.14);
     setVar2->workVariable = &var2;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar2);
 
     // Second write: var1 = var2 (cross-variable dependency in if statement)
-    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     list.addInstruction(readVar2);
     readVar2->workVariable = &var2;
 
@@ -2137,16 +2137,16 @@ TEST(LLVMTypeAnalyzer_VariableType, CrossVariableDependency_InIfStatement_QueryI
     var2Value.instruction = readVar2;
     readVar2->functionReturnReg = &var2Value;
 
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value });
     list.addInstruction(setVar1);
 
     // Query position inside if statement after assignments
-    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(queryPos);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(end);
 
     // var1 should have Number type from cross-variable dependency
@@ -2159,18 +2159,18 @@ TEST(LLVMTypeAnalyzer_VariableType, CrossVariableDependency_InIfStatement_QueryO
     LLVMInstructionList list;
     Variable var1("", ""), var2("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(start);
 
     // First write: var2 = 3.14 (Number type)
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 3.14);
     setVar2->workVariable = &var2;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar2);
 
     // Second write: var1 = var2 (cross-variable dependency in if statement)
-    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     list.addInstruction(readVar2);
     readVar2->workVariable = &var2;
 
@@ -2179,16 +2179,16 @@ TEST(LLVMTypeAnalyzer_VariableType, CrossVariableDependency_InIfStatement_QueryO
     var2Value.instruction = readVar2;
     readVar2->functionReturnReg = &var2Value;
 
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value });
     list.addInstruction(setVar1);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(end);
 
     // Query position outside if statement after it ends
-    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(queryPos);
 
     // var1 should return Unknown because the write is inside an if statement that may not execute
@@ -2202,7 +2202,7 @@ TEST(LLVMTypeAnalyzer_VariableType, SelfAssignment)
     Variable var1("", "");
 
     // No-op: var1 = var1
-    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     list.addInstruction(readVar1);
     readVar1->workVariable = &var1;
 
@@ -2211,13 +2211,13 @@ TEST(LLVMTypeAnalyzer_VariableType, SelfAssignment)
     var1Value.instruction = readVar1;
     readVar1->functionReturnReg = &var1Value;
 
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &var1Value });
     list.addInstruction(setVar1);
 
     // Query position after self-assignment
-    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(queryPos);
 
     // Should return the previous type because the write is a no-op
@@ -2231,14 +2231,14 @@ TEST(LLVMTypeAnalyzer_VariableType, SelfAssignmentWithTypeChange_Before)
     Variable var1("", "");
 
     // First write: var1 = 3.14 (Number type)
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 3.14);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // No-op: var1 = var1
-    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     list.addInstruction(readVar1);
     readVar1->workVariable = &var1;
 
@@ -2247,13 +2247,13 @@ TEST(LLVMTypeAnalyzer_VariableType, SelfAssignmentWithTypeChange_Before)
     var1Value.instruction = readVar1;
     readVar1->functionReturnReg = &var1Value;
 
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar2->workVariable = &var1;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &var1Value });
     list.addInstruction(setVar2);
 
     // Query position after self-assignment
-    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(queryPos);
 
     // Should return the previous type (number) because the write is a no-op
@@ -2267,7 +2267,7 @@ TEST(LLVMTypeAnalyzer_VariableType, SelfAssignmentWithTypeChange_After)
     Variable var1("", "");
 
     // No-op: var1 = var1
-    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     list.addInstruction(readVar1);
     readVar1->workVariable = &var1;
 
@@ -2276,20 +2276,20 @@ TEST(LLVMTypeAnalyzer_VariableType, SelfAssignmentWithTypeChange_After)
     var1Value.instruction = readVar1;
     readVar1->functionReturnReg = &var1Value;
 
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &var1Value });
     list.addInstruction(setVar1);
 
     // var1 = 3.14 (Number type)
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 3.14);
     setVar2->workVariable = &var1;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
     // Query position after real assignment
-    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(queryPos);
 
     // Should return number because it's assigned after the no-op
@@ -2303,7 +2303,7 @@ TEST(LLVMTypeAnalyzer_VariableType, InstructionReturnType_AddNumbers)
     Variable var1("", "");
 
     // Create add instruction: 5 + 3
-    auto addInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Add, nullptr, false);
+    auto addInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Add, false);
     LLVMConstantRegister operand1(Compiler::StaticType::Number, 5);
     LLVMConstantRegister operand2(Compiler::StaticType::Number, 3);
     addInstruction->args.push_back({ Compiler::StaticType::Number, &operand1 });
@@ -2317,13 +2317,13 @@ TEST(LLVMTypeAnalyzer_VariableType, InstructionReturnType_AddNumbers)
     list.addInstruction(addInstruction);
 
     // Assign add result to variable: var1 = (5 + 3)
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &addResult });
     list.addInstruction(setVar1);
 
     // Query position after the assignment
-    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(queryPos);
 
     // var1 should have Number type from add instruction return
@@ -2337,7 +2337,7 @@ TEST(LLVMTypeAnalyzer_VariableType, InstructionReturnType_StringConcat)
     Variable var1("", "");
 
     // Create string concatenation instruction: "hello" + "world"
-    auto concatInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::StringConcat, nullptr, false);
+    auto concatInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::StringConcat, false);
     LLVMConstantRegister str1(Compiler::StaticType::String, "hello");
     LLVMConstantRegister str2(Compiler::StaticType::String, "world");
     concatInstruction->args.push_back({ Compiler::StaticType::String, &str1 });
@@ -2351,13 +2351,13 @@ TEST(LLVMTypeAnalyzer_VariableType, InstructionReturnType_StringConcat)
     list.addInstruction(concatInstruction);
 
     // Assign concat result to variable: var1 = ("hello" + "world")
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &concatResult });
     list.addInstruction(setVar1);
 
     // Query position after the assignment
-    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(queryPos);
 
     // var1 should have String type from concat instruction return
@@ -2371,7 +2371,7 @@ TEST(LLVMTypeAnalyzer_VariableType, InstructionReturnType_MathFunction)
     Variable var1("", "");
 
     // Create sqrt instruction: sqrt(16)
-    auto sqrtInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Sqrt, nullptr, false);
+    auto sqrtInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Sqrt, false);
     LLVMConstantRegister operand(Compiler::StaticType::Number, 16);
     sqrtInstruction->args.push_back({ Compiler::StaticType::Number, &operand });
 
@@ -2383,13 +2383,13 @@ TEST(LLVMTypeAnalyzer_VariableType, InstructionReturnType_MathFunction)
     list.addInstruction(sqrtInstruction);
 
     // Assign sqrt result to variable: var1 = sqrt(16)
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &sqrtResult });
     list.addInstruction(setVar1);
 
     // Query position after the assignment
-    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(queryPos);
 
     // var1 should have Number type from sqrt instruction return
@@ -2403,7 +2403,7 @@ TEST(LLVMTypeAnalyzer_VariableType, InstructionReturnType_Comparison)
     Variable var1("", "");
 
     // Create comparison instruction: 5 > 3
-    auto cmpInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::CmpGT, nullptr, false);
+    auto cmpInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::CmpGT, false);
     LLVMConstantRegister operand1(Compiler::StaticType::Number, 5);
     LLVMConstantRegister operand2(Compiler::StaticType::Number, 3);
     cmpInstruction->args.push_back({ Compiler::StaticType::Number, &operand1 });
@@ -2417,13 +2417,13 @@ TEST(LLVMTypeAnalyzer_VariableType, InstructionReturnType_Comparison)
     list.addInstruction(cmpInstruction);
 
     // Assign comparison result to variable: var1 = (5 > 3)
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &cmpResult });
     list.addInstruction(setVar1);
 
     // Query position after the assignment
-    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(queryPos);
 
     // var1 should have Bool type from comparison instruction return
@@ -2437,7 +2437,7 @@ TEST(LLVMTypeAnalyzer_VariableType, InstructionReturnType_FunctionCall)
     Variable var1("", "");
 
     // Create function call instruction
-    auto funcInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     funcInstruction->functionName = "some_reporter_function";
     LLVMConstantRegister arg(Compiler::StaticType::Number, 42);
     funcInstruction->args.push_back({ Compiler::StaticType::Number, &arg });
@@ -2450,13 +2450,13 @@ TEST(LLVMTypeAnalyzer_VariableType, InstructionReturnType_FunctionCall)
     list.addInstruction(funcInstruction);
 
     // Assign function result to variable: var1 = some_reporter_function(42)
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &funcResult });
     list.addInstruction(setVar1);
 
     // Query position after the assignment
-    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(queryPos);
 
     // var1 should have String type from function call return
@@ -2470,7 +2470,7 @@ TEST(LLVMTypeAnalyzer_VariableType, InstructionReturnType_ChainedOperations)
     Variable var1("", "");
 
     // First operation: 5 + 3
-    auto addInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Add, nullptr, false);
+    auto addInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Add, false);
     LLVMConstantRegister operand1(Compiler::StaticType::Number, 5);
     LLVMConstantRegister operand2(Compiler::StaticType::Number, 3);
     addInstruction->args.push_back({ Compiler::StaticType::Number, &operand1 });
@@ -2483,7 +2483,7 @@ TEST(LLVMTypeAnalyzer_VariableType, InstructionReturnType_ChainedOperations)
     list.addInstruction(addInstruction);
 
     // Second operation: (5 + 3) * 2
-    auto mulInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Mul, nullptr, false);
+    auto mulInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Mul, false);
     LLVMConstantRegister multiplier(Compiler::StaticType::Number, 2);
     mulInstruction->args.push_back({ Compiler::StaticType::Unknown, &addResult });
     mulInstruction->args.push_back({ Compiler::StaticType::Number, &multiplier });
@@ -2495,13 +2495,13 @@ TEST(LLVMTypeAnalyzer_VariableType, InstructionReturnType_ChainedOperations)
     list.addInstruction(mulInstruction);
 
     // Assign final result to variable: var1 = ((5 + 3) * 2)
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &mulResult });
     list.addInstruction(setVar1);
 
     // Query position after the assignment
-    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(queryPos);
 
     // var1 should have Number type from chained operations
@@ -2515,11 +2515,11 @@ TEST(LLVMTypeAnalyzer_VariableType, InstructionReturnType_QueryBeforeAssignment)
     Variable var1("", "");
 
     // Query position before any operations
-    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto queryPos = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(queryPos);
 
     // Create add instruction: 5 + 3 (after query position)
-    auto addInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Add, nullptr, false);
+    auto addInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Add, false);
     LLVMConstantRegister operand1(Compiler::StaticType::Number, 5);
     LLVMConstantRegister operand2(Compiler::StaticType::Number, 3);
     addInstruction->args.push_back({ Compiler::StaticType::Number, &operand1 });
@@ -2532,7 +2532,7 @@ TEST(LLVMTypeAnalyzer_VariableType, InstructionReturnType_QueryBeforeAssignment)
     list.addInstruction(addInstruction);
 
     // Assign add result to variable: var1 = (5 + 3) (after query position)
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &addResult });
     list.addInstruction(setVar1);
diff --git a/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp b/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp
index c2964dd1..54d699fd 100644
--- a/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp
+++ b/test/llvm/type_analyzer/variabletypeafterbranch_test.cpp
@@ -18,13 +18,13 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NullVariable)
     LLVMTypeAnalyzer analyzer;
     LLVMInstructionList list;
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(nullptr, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
@@ -43,10 +43,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyLoop)
     Variable var("", "");
     LLVMInstructionList list;
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
@@ -58,10 +58,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyIfStatement)
     Variable var("", "");
     LLVMInstructionList list;
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(start);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
@@ -73,13 +73,13 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyIfElseStatement_IfBranch)
     Variable var("", "");
     LLVMInstructionList list;
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(start);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     list.addInstruction(elseStart);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
@@ -91,13 +91,13 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyIfElseStatement_ElseBranch)
     Variable var("", "");
     LLVMInstructionList list;
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(start);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     list.addInstruction(elseStart);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, elseStart.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
@@ -109,10 +109,10 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, EmptyLoopUnknownType)
     Variable var("", "");
     LLVMInstructionList list;
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown);
@@ -124,13 +124,13 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NoWriteOperations)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcCall = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     list.addInstruction(funcCall);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
@@ -142,16 +142,16 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteSameTypeNumber)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 1.25);
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
@@ -163,16 +163,16 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteSameTypeBool)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::Bool, true);
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::Bool);
@@ -184,16 +184,16 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteSameTypeString)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::String), Compiler::StaticType::String);
@@ -205,16 +205,16 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteStringOptimization)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "1.25");
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     // Although string is assigned, it's constant and represents a number
@@ -228,24 +228,24 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteMultipleVariables)
     Variable var1("", "");
     Variable var2("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
     // Set var1
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 6);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Set var2
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     setVar2->workVariable = &var2;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var1, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
@@ -257,16 +257,16 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteFromUnknownType)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMRegister value(Compiler::StaticType::Unknown);
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
@@ -278,16 +278,16 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteToUnknownType)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 5);
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Number);
@@ -299,16 +299,16 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteUnknownToUnknownType)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMRegister value(Compiler::StaticType::Unknown);
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Unknown), Compiler::StaticType::Unknown);
@@ -320,16 +320,16 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeNumberToS
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "test");
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
@@ -341,16 +341,16 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeStringToN
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 5.8);
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::String), Compiler::StaticType::Number);
@@ -362,16 +362,16 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeNumberToB
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::Bool, true);
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Bool);
@@ -383,16 +383,16 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeBoolToNum
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 1);
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number);
@@ -404,16 +404,16 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeBoolToStr
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::String, "abc");
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::String);
@@ -425,16 +425,16 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentTypeStringToB
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::Bool, false);
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::String), Compiler::StaticType::Bool);
@@ -446,16 +446,16 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteSameType_IfStatement)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(start);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 1.25);
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
@@ -467,16 +467,16 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SingleWriteDifferentType_IfStatem
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(start);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 5.8);
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::String), Compiler::StaticType::Number);
@@ -488,24 +488,24 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameTypeNumber)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
     // First write: string "abc" (incompatible with Number)
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "abc");
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Second write: number 5.25 (compatible with Number pre-loop type)
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 5.25);
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     // Should return false because final assignment is compatible with pre-loop Number type
@@ -518,24 +518,24 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameTypeString)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
     // First write: number 42 (incompatible with String)
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Second write: string "hello" (compatible with String pre-loop type)
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "hello");
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     // Should return false because final assignment is compatible with pre-loop String type
@@ -548,24 +548,24 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameTypeUnknown)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
     // First write: unknown type
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMRegister value1(Compiler::StaticType::Unknown);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Second write: string "hello" (compatible with String pre-loop type)
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "hello");
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     // Should return false because final assignment is compatible with pre-loop String type
@@ -578,24 +578,24 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesWithStringOptimizat
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
     // First write: string "abc" (incompatible with Number)
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "abc");
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Second write: string "3.14" (optimized to Number, compatible with pre-loop type)
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "3.14");
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     // Should return false because final assignment is optimized to Number type
@@ -608,24 +608,24 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesNumberToString)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
     // First write: number 42 (compatible with Number)
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Second write: string "hello" (incompatible with Number pre-loop type)
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "hello");
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     // Should return true because final assignment is incompatible with pre-loop Number type
@@ -638,24 +638,24 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesBoolToNumber)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
     // First write: compatible with Bool
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Bool, true);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Second write: number 4.25 (incompatible with Bool pre-loop type)
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 4.25);
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::Number);
@@ -667,24 +667,24 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesBoolToString)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
     // First write: compatible with Bool
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Bool, true);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Second write: string "hello" (incompatible with Bool pre-loop type)
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "hello");
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::String);
@@ -696,24 +696,24 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameType_IfStatemen
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(start);
 
     // First write: string "abc" (incompatible with Number)
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "abc");
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Second write: number 5.25 (compatible with Number type)
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 5.25);
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(end);
 
     // Should return false because final assignment is compatible with Number type
@@ -726,34 +726,34 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameType_IfBranch)
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(start);
 
     // First write: string "abc" (incompatible with Number)
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "abc");
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Second write: number 5.25 (compatible with Number type)
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 5.25);
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     list.addInstruction(elseStart);
 
     // Else branch write: string "test" (incompatible with Number type)
-    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value3(Compiler::StaticType::String, "test");
     setVar3->workVariable = &var;
     setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     list.addInstruction(setVar3);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(end);
 
     // Should return false because final assignment is compatible with Number type
@@ -766,34 +766,34 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesSameType_ElseBranch
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(start);
 
     // First write: string "abc" (incompatible with Number)
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "abc");
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     list.addInstruction(elseStart);
 
     // Else branch first write: string "abc" (incompatible with Number)
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "abc");
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
     // Else branch second write: number 5.25 (compatible with Number type)
-    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value3(Compiler::StaticType::Number, 5.25);
     setVar3->workVariable = &var;
     setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     list.addInstruction(setVar3);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(end);
 
     // Should return false because final assignment is compatible with Number type
@@ -806,24 +806,24 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesDifferentTypes_IfSt
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(start);
 
     // First write: compatible with Bool
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Bool, true);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Second write: string "hello" (incompatible with Bool type)
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "hello");
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::String);
@@ -835,34 +835,34 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesDifferentTypes_IfBr
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(start);
 
     // First write: compatible with Bool
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Bool, true);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Second write: string "hello" (incompatible with Bool type)
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "hello");
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     list.addInstruction(elseStart);
 
     // Else branch write: compatible with Bool
-    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value3(Compiler::StaticType::Bool, true);
     setVar3->workVariable = &var;
     setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     list.addInstruction(setVar3);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Bool), Compiler::StaticType::String);
@@ -874,34 +874,34 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleWritesDifferentTypes_Else
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(start);
 
     // First write: compatible with Bool
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Bool, true);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     list.addInstruction(elseStart);
 
     // First else branch write: compatible with Bool
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Bool, true);
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
     // Second else branch write: string "hello" (incompatible with Bool type)
-    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value3(Compiler::StaticType::String, "hello");
     setVar3->workVariable = &var;
     setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     list.addInstruction(setVar3);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, elseStart.get(), Compiler::StaticType::Bool), Compiler::StaticType::String);
@@ -913,33 +913,33 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoop_TypeChangeInIfB
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(ifStart);
 
     // First write - changes type
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "test");
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     list.addInstruction(elseStart);
 
     // Second write - does not change type
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 42);
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(ifEnd);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     // Returns unknown type because the type-changing branch might or might not run
@@ -952,33 +952,33 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoop_TypeChangeInEls
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(ifStart);
 
     // First write - does not change type
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     list.addInstruction(elseStart);
 
     // Second write - changes type
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(ifEnd);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     // Returns unknown type because the type-changing branch might or might not run
@@ -991,33 +991,33 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoop_IfElseWithoutTy
     LLVMInstructionList list;
     Variable var("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(ifStart);
 
     // First write - does not change type
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
-    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto elseStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     list.addInstruction(elseStart);
 
     // Second write - does not change type
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 1.25);
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(ifEnd);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, start.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
@@ -1030,33 +1030,33 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopWithTypeChange)
     Variable var("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(outerLoop);
 
     // Variable write inside outer loop
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Inner loop begin
-    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(innerLoop);
 
     // Variable write inside inner loop
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
     // Inner loop end
-    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(innerEnd);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(outerEnd);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
@@ -1069,33 +1069,33 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopWithoutTypeChange)
     Variable var("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginWhileLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginWhileLoop, false);
     list.addInstruction(outerLoop);
 
     // Variable write inside outer loop
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Inner loop begin
-    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(innerLoop);
 
     // Variable write inside inner loop
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 2.5);
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
     // Inner loop end
-    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(innerEnd);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(outerEnd);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
@@ -1108,40 +1108,40 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopTypeChangesButResets)
     Variable var("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(outerLoop);
 
     // Variable write inside outer loop
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Inner loop begin
-    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false);
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, false);
     list.addInstruction(innerLoop);
 
     // Variable write inside inner loop
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
     // Inner loop end
-    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(innerEnd);
 
     // Variable write after inner loop - resets type
-    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value3(Compiler::StaticType::Number, 2);
     setVar3->workVariable = &var;
     setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     list.addInstruction(setVar3);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(outerEnd);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
@@ -1154,40 +1154,40 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopTypeChangesAndDoesNotRe
     Variable var("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(outerLoop);
 
     // Variable write inside outer loop
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Inner loop begin
-    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginWhileLoop, nullptr, false);
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginWhileLoop, false);
     list.addInstruction(innerLoop);
 
     // Variable write inside inner loop
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::String, "test");
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
     // Inner loop end
-    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(innerEnd);
 
     // Variable write after inner loop - keeps the different type
-    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value3(Compiler::StaticType::String, "abc");
     setVar3->workVariable = &var;
     setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     list.addInstruction(setVar3);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(outerEnd);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::String);
@@ -1200,33 +1200,33 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, NestedLoopWithTypeChangeBeforeLoo
     Variable var("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, false);
     list.addInstruction(outerLoop);
 
     // Variable write inside outer loop
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "test");
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Inner loop begin
-    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(innerLoop);
 
     // Variable write inside inner loop
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 5);
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
     // Inner loop end
-    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(innerEnd);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(outerEnd);
 
     // Returns unknown type because loops can be skipped
@@ -1240,37 +1240,37 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoopWithTypeChangeBe
     Variable var("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, false);
     list.addInstruction(outerLoop);
 
     // Variable write inside outer loop
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "test");
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Inner if statement begin
-    auto innerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto innerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(innerIf);
 
     // Variable write inside inner if statement if branch
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 5);
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
     // Inner if statement else branch begin
-    auto innerElse = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto innerElse = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     list.addInstruction(innerElse);
 
     // Inner if statement end
-    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(innerEnd);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(outerEnd);
 
     // Returns unknown type because if statements can be skipped
@@ -1284,37 +1284,37 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoopWithTypeChangeBe
     Variable var("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, false);
     list.addInstruction(outerLoop);
 
     // Variable write inside outer loop
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "test");
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Inner if statement begin
-    auto innerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto innerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(innerIf);
 
     // Inner if statement else branch begin
-    auto innerElse = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto innerElse = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     list.addInstruction(innerElse);
 
     // Variable write inside inner if statement else branch
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 5);
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
     // Inner if statement end
-    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(innerEnd);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(outerEnd);
 
     // Returns unknown type because if statements can be skipped
@@ -1328,43 +1328,43 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, IfStatementInLoopWithTypeChangeBe
     Variable var("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatUntilLoop, false);
     list.addInstruction(outerLoop);
 
     // Variable write inside outer loop
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "test");
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Inner if statement begin
-    auto innerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto innerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(innerIf);
 
-    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value(Compiler::StaticType::Number, 5);
     setVar->workVariable = &var;
     setVar->args.push_back({ Compiler::StaticType::Unknown, &value });
     list.addInstruction(setVar);
 
     // Inner if statement else branch begin
-    auto innerElse = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto innerElse = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     list.addInstruction(innerElse);
 
     // Variable write inside inner if statement else branch
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 5);
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
     // Inner if statement end
-    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto innerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(innerEnd);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(outerEnd);
 
     // Returns number type because the type always changes to number
@@ -1378,48 +1378,48 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedLoopsWithTypeChange
     Variable var("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(outerLoop);
 
     // Variable write inside outer loop
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Inner loop 1 begin
-    auto innerLoop1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(innerLoop1);
 
     // Variable write inside inner loop 1
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75);
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
     // Inner loop 2 begin
-    auto innerLoop2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(innerLoop2);
 
     // Variable write inside inner loop 2
-    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value3(Compiler::StaticType::String, "abc");
     setVar3->workVariable = &var;
     setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     list.addInstruction(setVar3);
 
     // Inner loop 2 end
-    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(innerEnd2);
 
     // Inner loop 1 end
-    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(innerEnd1);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(outerEnd);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
@@ -1432,48 +1432,48 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedLoopsWithTypeChange
     Variable var("", "");
 
     // Outer loop begin
-    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto outerLoop = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(outerLoop);
 
     // Variable write inside outer loop
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Inner loop 1 begin
-    auto innerLoop1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(innerLoop1);
 
     // Inner loop 2 begin
-    auto innerLoop2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto innerLoop2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(innerLoop2);
 
     // Variable write inside inner loop 2
-    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value3(Compiler::StaticType::String, "abc");
     setVar3->workVariable = &var;
     setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     list.addInstruction(setVar3);
 
     // Inner loop 2 end
-    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(innerEnd2);
 
     // Variable write inside inner loop 1 - resets type
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75);
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
     // Inner loop 1 end
-    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(innerEnd1);
 
     // Outer loop end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(outerEnd);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerLoop.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
@@ -1486,59 +1486,59 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedIfStatementsWithTyp
     Variable var("", "");
 
     // Outer if statement begin
-    auto outerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto outerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(outerIf);
 
     // Variable write inside outer if statement
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Inner if statement 1 begin
-    auto innerIf1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto innerIf1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(innerIf1);
 
     // Variable write inside inner if statement 1
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75);
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
     // Inner if statement 2 begin
-    auto innerIf2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto innerIf2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(innerIf2);
 
     // Variable write inside inner if statement 2
-    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value3(Compiler::StaticType::String, "abc");
     setVar3->workVariable = &var;
     setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     list.addInstruction(setVar3);
 
     // Inner if statement 2 else branch
-    auto innerElse2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto innerElse2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     list.addInstruction(innerElse2);
 
     // Variable write inside inner if statement 2 else branch
-    auto setVar4 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar4 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value4(Compiler::StaticType::Number, 4);
     setVar4->workVariable = &var;
     setVar4->args.push_back({ Compiler::StaticType::Unknown, &value4 });
     list.addInstruction(setVar4);
 
     // Inner if statement 2 end
-    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(innerEnd2);
 
     // Inner if statement 1 end
-    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(innerEnd1);
 
     // Outer if statement end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(outerEnd);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerIf.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
@@ -1551,59 +1551,59 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedIfStatementsWithTyp
     Variable var("", "");
 
     // Outer if statement begin
-    auto outerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto outerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(outerIf);
 
     // Variable write inside outer if statement
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Inner if statement 1 begin
-    auto innerIf1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto innerIf1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(innerIf1);
 
     // Variable write inside inner if statement 1
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75);
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
     // Inner if statement 2 begin
-    auto innerIf2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto innerIf2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(innerIf2);
 
     // Variable write inside inner if statement 2
-    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value3(Compiler::StaticType::Number, 4);
     setVar3->workVariable = &var;
     setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     list.addInstruction(setVar3);
 
     // Inner if statement 2 else branch
-    auto innerElse2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto innerElse2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     list.addInstruction(innerElse2);
 
     // Variable write inside inner if statement 2 else branch
-    auto setVar4 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar4 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value4(Compiler::StaticType::String, "abc");
     setVar4->workVariable = &var;
     setVar4->args.push_back({ Compiler::StaticType::Unknown, &value4 });
     list.addInstruction(setVar4);
 
     // Inner if statement 2 end
-    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(innerEnd2);
 
     // Inner if statement 1 end
-    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(innerEnd1);
 
     // Outer if statement end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(outerEnd);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerIf.get(), Compiler::StaticType::Number), Compiler::StaticType::Unknown);
@@ -1616,59 +1616,59 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, MultipleNestedIfStatementsWithout
     Variable var("", "");
 
     // Outer if statement begin
-    auto outerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto outerIf = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(outerIf);
 
     // Variable write inside outer if statement
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 5);
     setVar1->workVariable = &var;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Inner if statement 1 begin
-    auto innerIf1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto innerIf1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(innerIf1);
 
     // Variable write inside inner if statement 1
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 2.75);
     setVar2->workVariable = &var;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
     // Inner if statement 2 begin
-    auto innerIf2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto innerIf2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(innerIf2);
 
     // Variable write inside inner if statement 2
-    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value3(Compiler::StaticType::Number, 4);
     setVar3->workVariable = &var;
     setVar3->args.push_back({ Compiler::StaticType::Unknown, &value3 });
     list.addInstruction(setVar3);
 
     // Inner if statement 2 else branch
-    auto innerElse2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, nullptr, false);
+    auto innerElse2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginElse, false);
     list.addInstruction(innerElse2);
 
     // Variable write inside inner if statement 2 else branch
-    auto setVar4 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar4 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value4(Compiler::StaticType::Number, 0);
     setVar4->workVariable = &var;
     setVar4->args.push_back({ Compiler::StaticType::Unknown, &value4 });
     list.addInstruction(setVar4);
 
     // Inner if statement 2 end
-    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto innerEnd2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(innerEnd2);
 
     // Inner if statement 1 end
-    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto innerEnd1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(innerEnd1);
 
     // Outer if statement end
-    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto outerEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(outerEnd);
 
     ASSERT_EQ(analyzer.variableTypeAfterBranch(&var, outerIf.get(), Compiler::StaticType::Number), Compiler::StaticType::Number);
@@ -1680,18 +1680,18 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_SimpleAss
     LLVMInstructionList list;
     Variable var1("", ""), var2("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
     // First write: var2 = "test" (String type)
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "test");
     setVar2->workVariable = &var2;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar2);
 
     // Second write: var1 = var2 (cross-variable dependency)
-    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     list.addInstruction(readVar2);
     readVar2->workVariable = &var2;
 
@@ -1700,12 +1700,12 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_SimpleAss
     var2Value.instruction = readVar2;
     readVar2->functionReturnReg = &var2Value;
 
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value });
     list.addInstruction(setVar1);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     // var1 should have String type due to cross-variable dependency
@@ -1718,18 +1718,18 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_TypeMisma
     LLVMInstructionList list;
     Variable var1("", ""), var2("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
     // First write: var2 = "test" (String type)
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::String, "test");
     setVar2->workVariable = &var2;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar2);
 
     // Second write: var1 = var2 (cross-variable dependency with type mismatch)
-    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     list.addInstruction(readVar2);
     readVar2->workVariable = &var2;
 
@@ -1738,12 +1738,12 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_TypeMisma
     var2Value.instruction = readVar2;
     readVar2->functionReturnReg = &var2Value;
 
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value });
     list.addInstruction(setVar1);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     // var1 should have String type (incompatible with Number pre-loop type)
@@ -1756,11 +1756,11 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_SimpleAss
     LLVMInstructionList list;
     Variable var1("", ""), var2("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
     // var1 = var2
-    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     list.addInstruction(readVar2);
     readVar2->workVariable = &var2;
 
@@ -1769,19 +1769,19 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_SimpleAss
     var2Value.instruction = readVar2;
     readVar2->functionReturnReg = &var2Value;
 
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value });
     list.addInstruction(setVar1);
 
     // var2 = 5.2 (type resets to number)
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 5.2);
     setVar2->workVariable = &var2;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     // Although the type of var2 is changed to number, it's unknown before the first iteration
@@ -1794,18 +1794,18 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_ChainedAs
     LLVMInstructionList list;
     Variable var1("", ""), var2("", ""), var3("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
     // First write: var3 = 42 (Number type)
-    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
     setVar3->workVariable = &var3;
     setVar3->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar3);
 
     // Second write: var2 = var3 (cross-variable dependency)
-    auto readVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     list.addInstruction(readVar3);
     readVar3->workVariable = &var3;
 
@@ -1814,13 +1814,13 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_ChainedAs
     var3Value.instruction = readVar3;
     readVar3->functionReturnReg = &var3Value;
 
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar2->workVariable = &var2;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &var3Value });
     list.addInstruction(setVar2);
 
     // Third write: var1 = var2 (chained cross-variable dependency)
-    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     list.addInstruction(readVar2);
     readVar2->workVariable = &var2;
 
@@ -1829,12 +1829,12 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_ChainedAs
     var2Value.instruction = readVar2;
     readVar2->functionReturnReg = &var2Value;
 
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value });
     list.addInstruction(setVar1);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     // var1 should have Number type through the chain var1 = var2 = var3 = 42
@@ -1847,11 +1847,11 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_CircularR
     LLVMInstructionList list;
     Variable var1("", ""), var2("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
     // First write: var1 = var2 (circular dependency setup)
-    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     list.addInstruction(readVar2);
     readVar2->workVariable = &var2;
 
@@ -1860,13 +1860,13 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_CircularR
     var2Value.instruction = readVar2;
     readVar2->functionReturnReg = &var2Value;
 
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value });
     list.addInstruction(setVar1);
 
     // Second write: var2 = var1 (completes circular dependency)
-    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     list.addInstruction(readVar1);
     readVar1->workVariable = &var1;
 
@@ -1875,12 +1875,12 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_CircularR
     var1Value.instruction = readVar1;
     readVar1->functionReturnReg = &var1Value;
 
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar2->workVariable = &var2;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &var1Value });
     list.addInstruction(setVar2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     // Should return Unknown due to circular dependency
@@ -1893,25 +1893,25 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_CircularR
     LLVMInstructionList list;
     Variable var1("", ""), var2("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
     // var1 is a number
-    auto setupVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setupVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
     setupVar1->workVariable = &var1;
     setupVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setupVar1);
 
     // var2 is a number
-    auto setupVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setupVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 42);
     setupVar2->workVariable = &var2;
     setupVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setupVar2);
 
     // First write: var1 = var2 (circular dependency setup)
-    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     list.addInstruction(readVar2);
     readVar2->workVariable = &var2;
 
@@ -1920,13 +1920,13 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_CircularR
     var2Value.instruction = readVar2;
     readVar2->functionReturnReg = &var2Value;
 
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value });
     list.addInstruction(setVar1);
 
     // Second write: var2 = var1 (completes circular dependency)
-    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     list.addInstruction(readVar1);
     readVar1->workVariable = &var1;
 
@@ -1935,12 +1935,12 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_CircularR
     var1Value.instruction = readVar1;
     readVar1->functionReturnReg = &var1Value;
 
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar2->workVariable = &var2;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &var1Value });
     list.addInstruction(setVar2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     // Although there is a circular dependency, the types of both variables are known
@@ -1953,20 +1953,20 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_CircularR
     LLVMInstructionList list;
     Variable var1("", ""), var2("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
     // var1: unknown type
 
     // var2 is a number
-    auto setupVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setupVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 42);
     setupVar2->workVariable = &var2;
     setupVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setupVar2);
 
     // First write: var1 = var2 (circular dependency setup)
-    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     list.addInstruction(readVar2);
     readVar2->workVariable = &var2;
 
@@ -1975,13 +1975,13 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_CircularR
     var2Value.instruction = readVar2;
     readVar2->functionReturnReg = &var2Value;
 
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value });
     list.addInstruction(setVar1);
 
     // Second write: var2 = var1 (completes circular dependency)
-    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     list.addInstruction(readVar1);
     readVar1->workVariable = &var1;
 
@@ -1990,12 +1990,12 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_CircularR
     var1Value.instruction = readVar1;
     readVar1->functionReturnReg = &var1Value;
 
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar2->workVariable = &var2;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &var1Value });
     list.addInstruction(setVar2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     // Although there is a circular dependency, the type of var2 is known and this variable is assigned to var1
@@ -2008,11 +2008,11 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_CircularR
     LLVMInstructionList list;
     Variable var1("", ""), var2("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
     // var1 is a number
-    auto setupVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setupVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 42);
     setupVar1->workVariable = &var1;
     setupVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
@@ -2021,7 +2021,7 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_CircularR
     // var2: unknown type
 
     // First write: var1 = var2 (circular dependency setup)
-    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     list.addInstruction(readVar2);
     readVar2->workVariable = &var2;
 
@@ -2030,13 +2030,13 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_CircularR
     var2Value.instruction = readVar2;
     readVar2->functionReturnReg = &var2Value;
 
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value });
     list.addInstruction(setVar1);
 
     // Second write: var2 = var1 (completes circular dependency)
-    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     list.addInstruction(readVar1);
     readVar1->workVariable = &var1;
 
@@ -2045,12 +2045,12 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_CircularR
     var1Value.instruction = readVar1;
     readVar1->functionReturnReg = &var1Value;
 
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar2->workVariable = &var2;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &var1Value });
     list.addInstruction(setVar2);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     // The type of var2 is not known and this variable is assigned to var1
@@ -2063,11 +2063,11 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_ChainedCi
     LLVMInstructionList list;
     Variable var1("", ""), var2("", ""), var3("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
     // First write: var1 = var2 (circular dependency setup)
-    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     list.addInstruction(readVar2);
     readVar2->workVariable = &var2;
 
@@ -2076,13 +2076,13 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_ChainedCi
     var2Value.instruction = readVar2;
     readVar2->functionReturnReg = &var2Value;
 
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value });
     list.addInstruction(setVar1);
 
     // Second write: var2 = var3
-    auto readVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     list.addInstruction(readVar3);
     readVar3->workVariable = &var3;
 
@@ -2091,13 +2091,13 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_ChainedCi
     var3Value.instruction = readVar3;
     readVar3->functionReturnReg = &var3Value;
 
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar2->workVariable = &var2;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &var3Value });
     list.addInstruction(setVar2);
 
     // Third write: var3 = var1 (completes circular dependency)
-    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     list.addInstruction(readVar1);
     readVar1->workVariable = &var1;
 
@@ -2106,12 +2106,12 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_ChainedCi
     var1Value.instruction = readVar1;
     readVar1->functionReturnReg = &var1Value;
 
-    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar3 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar3->workVariable = &var3;
     setVar3->args.push_back({ Compiler::StaticType::Unknown, &var1Value });
     list.addInstruction(setVar3);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     // Should return Unknown due to circular dependency
@@ -2124,18 +2124,18 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_InIfState
     LLVMInstructionList list;
     Variable var1("", ""), var2("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(start);
 
     // First write: var2 = 3.14 (Number type)
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 3.14);
     setVar2->workVariable = &var2;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar2);
 
     // Second write: var1 = var2 (cross-variable dependency in if statement)
-    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     list.addInstruction(readVar2);
     readVar2->workVariable = &var2;
 
@@ -2144,12 +2144,12 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, CrossVariableDependency_InIfState
     var2Value.instruction = readVar2;
     readVar2->functionReturnReg = &var2Value;
 
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &var2Value });
     list.addInstruction(setVar1);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(end);
 
     // var1 should have Number type from cross-variable dependency
@@ -2162,15 +2162,15 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SelfAssignment)
     LLVMInstructionList list;
     Variable var1("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
     // Start if statement
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(ifStart);
 
     // No-op: var1 = var1
-    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     list.addInstruction(readVar1);
     readVar1->workVariable = &var1;
 
@@ -2179,17 +2179,17 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SelfAssignment)
     var1Value.instruction = readVar1;
     readVar1->functionReturnReg = &var1Value;
 
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &var1Value });
     list.addInstruction(setVar1);
 
     // End if statement
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(ifEnd);
 
     // End loop
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     // Should return the previous type because the write is a no-op
@@ -2202,22 +2202,22 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SelfAssignmentWithTypeChange_Befo
     LLVMInstructionList list;
     Variable var1("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
     // First write: var1 = 3.14 (Number type)
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value1(Compiler::StaticType::Number, 3.14);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &value1 });
     list.addInstruction(setVar1);
 
     // Start if statement
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(ifStart);
 
     // No-op: var1 = var1
-    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     list.addInstruction(readVar1);
     readVar1->workVariable = &var1;
 
@@ -2226,17 +2226,17 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SelfAssignmentWithTypeChange_Befo
     var1Value.instruction = readVar1;
     readVar1->functionReturnReg = &var1Value;
 
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar2->workVariable = &var1;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &var1Value });
     list.addInstruction(setVar2);
 
     // End if statement
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(ifEnd);
 
     // End loop
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     // Should return the previous type (number) because the write is a no-op
@@ -2249,15 +2249,15 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SelfAssignmentWithTypeChange_Afte
     LLVMInstructionList list;
     Variable var1("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
     // Start if statement
-    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, nullptr, false);
+    auto ifStart = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginIf, false);
     list.addInstruction(ifStart);
 
     // No-op: var1 = var1
-    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, nullptr, false);
+    auto readVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, false);
     list.addInstruction(readVar1);
     readVar1->workVariable = &var1;
 
@@ -2266,24 +2266,24 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, SelfAssignmentWithTypeChange_Afte
     var1Value.instruction = readVar1;
     readVar1->functionReturnReg = &var1Value;
 
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &var1Value });
     list.addInstruction(setVar1);
 
     // End if statement
-    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, nullptr, false);
+    auto ifEnd = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndIf, false);
     list.addInstruction(ifEnd);
 
     // var1 = 3.14 (Number type)
-    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar2 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     LLVMConstantRegister value2(Compiler::StaticType::Number, 3.14);
     setVar2->workVariable = &var1;
     setVar2->args.push_back({ Compiler::StaticType::Unknown, &value2 });
     list.addInstruction(setVar2);
 
     // End loop
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     // Should return number because it's assigned later in the loop
@@ -2296,11 +2296,11 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, InstructionReturnType_AddNumbers)
     LLVMInstructionList list;
     Variable var1("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
     // Create add instruction: 5 + 3
-    auto addInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Add, nullptr, false);
+    auto addInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Add, false);
     LLVMConstantRegister operand1(Compiler::StaticType::Number, 5);
     LLVMConstantRegister operand2(Compiler::StaticType::Number, 3);
     addInstruction->args.push_back({ Compiler::StaticType::Number, &operand1 });
@@ -2314,12 +2314,12 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, InstructionReturnType_AddNumbers)
     list.addInstruction(addInstruction);
 
     // Assign add result to variable: var1 = (5 + 3)
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &addResult });
     list.addInstruction(setVar1);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     // var1 should have Number type from add instruction return
@@ -2332,11 +2332,11 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, InstructionReturnType_StringConca
     LLVMInstructionList list;
     Variable var1("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
     // Create string concatenation instruction: "hello" + "world"
-    auto concatInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::StringConcat, nullptr, false);
+    auto concatInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::StringConcat, false);
     LLVMConstantRegister str1(Compiler::StaticType::String, "hello");
     LLVMConstantRegister str2(Compiler::StaticType::String, "world");
     concatInstruction->args.push_back({ Compiler::StaticType::String, &str1 });
@@ -2350,12 +2350,12 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, InstructionReturnType_StringConca
     list.addInstruction(concatInstruction);
 
     // Assign concat result to variable: var1 = ("hello" + "world")
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &concatResult });
     list.addInstruction(setVar1);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     // var1 should have String type from concat instruction return
@@ -2368,11 +2368,11 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, InstructionReturnType_MathFunctio
     LLVMInstructionList list;
     Variable var1("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
     // Create sqrt instruction: sqrt(16)
-    auto sqrtInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Sqrt, nullptr, false);
+    auto sqrtInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Sqrt, false);
     LLVMConstantRegister operand(Compiler::StaticType::Number, 16);
     sqrtInstruction->args.push_back({ Compiler::StaticType::Number, &operand });
 
@@ -2384,12 +2384,12 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, InstructionReturnType_MathFunctio
     list.addInstruction(sqrtInstruction);
 
     // Assign sqrt result to variable: var1 = sqrt(16)
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &sqrtResult });
     list.addInstruction(setVar1);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     // var1 should have Number type from sqrt instruction return
@@ -2402,11 +2402,11 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, InstructionReturnType_Comparison)
     LLVMInstructionList list;
     Variable var1("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
     // Create comparison instruction: 5 > 3
-    auto cmpInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::CmpGT, nullptr, false);
+    auto cmpInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::CmpGT, false);
     LLVMConstantRegister operand1(Compiler::StaticType::Number, 5);
     LLVMConstantRegister operand2(Compiler::StaticType::Number, 3);
     cmpInstruction->args.push_back({ Compiler::StaticType::Number, &operand1 });
@@ -2420,12 +2420,12 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, InstructionReturnType_Comparison)
     list.addInstruction(cmpInstruction);
 
     // Assign comparison result to variable: var1 = (5 > 3)
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &cmpResult });
     list.addInstruction(setVar1);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     // var1 should have Bool type from comparison instruction return
@@ -2438,11 +2438,11 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, InstructionReturnType_FunctionCal
     LLVMInstructionList list;
     Variable var1("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
     // Create function call instruction
-    auto funcInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, nullptr, false);
+    auto funcInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::FunctionCall, false);
     funcInstruction->functionName = "some_reporter_function";
     LLVMConstantRegister arg(Compiler::StaticType::Number, 42);
     funcInstruction->args.push_back({ Compiler::StaticType::Number, &arg });
@@ -2455,12 +2455,12 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, InstructionReturnType_FunctionCal
     list.addInstruction(funcInstruction);
 
     // Assign function result to variable: var1 = some_reporter_function(42)
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &funcResult });
     list.addInstruction(setVar1);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     // var1 should have String type from function call return
@@ -2473,11 +2473,11 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, InstructionReturnType_ChainedOper
     LLVMInstructionList list;
     Variable var1("", "");
 
-    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, nullptr, false);
+    auto start = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::BeginRepeatLoop, false);
     list.addInstruction(start);
 
     // First operation: 5 + 3
-    auto addInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Add, nullptr, false);
+    auto addInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Add, false);
     LLVMConstantRegister operand1(Compiler::StaticType::Number, 5);
     LLVMConstantRegister operand2(Compiler::StaticType::Number, 3);
     addInstruction->args.push_back({ Compiler::StaticType::Number, &operand1 });
@@ -2490,7 +2490,7 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, InstructionReturnType_ChainedOper
     list.addInstruction(addInstruction);
 
     // Second operation: (5 + 3) * 2
-    auto mulInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Mul, nullptr, false);
+    auto mulInstruction = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::Mul, false);
     LLVMConstantRegister multiplier(Compiler::StaticType::Number, 2);
     mulInstruction->args.push_back({ Compiler::StaticType::Unknown, &addResult });
     mulInstruction->args.push_back({ Compiler::StaticType::Number, &multiplier });
@@ -2502,12 +2502,12 @@ TEST(LLVMTypeAnalyzer_VariableTypeAfterBranch, InstructionReturnType_ChainedOper
     list.addInstruction(mulInstruction);
 
     // Assign final result to variable: var1 = ((5 + 3) * 2)
-    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, nullptr, false);
+    auto setVar1 = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::WriteVariable, false);
     setVar1->workVariable = &var1;
     setVar1->args.push_back({ Compiler::StaticType::Unknown, &mulResult });
     list.addInstruction(setVar1);
 
-    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, nullptr, false);
+    auto end = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::EndLoop, false);
     list.addInstruction(end);
 
     // var1 should have Number type from chained operations

From b69af819a62b04a414493557e8a562bd491a6fc8 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Mon, 4 Aug 2025 13:10:03 +0200
Subject: [PATCH 64/79] Move LLVM helpers to a new class

---
 src/engine/internal/llvm/CMakeLists.txt      |    2 +
 src/engine/internal/llvm/llvmbuildutils.cpp  |  993 ++++++++++++++
 src/engine/internal/llvm/llvmbuildutils.h    |  101 ++
 src/engine/internal/llvm/llvmcodebuilder.cpp | 1263 +++---------------
 src/engine/internal/llvm/llvmcodebuilder.h   |   50 +-
 5 files changed, 1253 insertions(+), 1156 deletions(-)
 create mode 100644 src/engine/internal/llvm/llvmbuildutils.cpp
 create mode 100644 src/engine/internal/llvm/llvmbuildutils.h

diff --git a/src/engine/internal/llvm/CMakeLists.txt b/src/engine/internal/llvm/CMakeLists.txt
index 18814476..b5d79d2a 100644
--- a/src/engine/internal/llvm/CMakeLists.txt
+++ b/src/engine/internal/llvm/CMakeLists.txt
@@ -1,5 +1,7 @@
 target_sources(scratchcpp
   PRIVATE
+    llvmbuildutils.cpp
+    llvmbuildutils.h
     llvmcodebuilder.cpp
     llvmcodebuilder.h
     llvmregister.h
diff --git a/src/engine/internal/llvm/llvmbuildutils.cpp b/src/engine/internal/llvm/llvmbuildutils.cpp
new file mode 100644
index 00000000..472b6b19
--- /dev/null
+++ b/src/engine/internal/llvm/llvmbuildutils.cpp
@@ -0,0 +1,993 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#include <scratchcpp/target.h>
+#include <scratchcpp/variable.h>
+#include <scratchcpp/list.h>
+
+#include "llvmbuildutils.h"
+#include "llvmfunctions.h"
+#include "llvmcompilercontext.h"
+#include "llvmregister.h"
+
+using namespace libscratchcpp;
+
+static std::unordered_map<ValueType, Compiler::StaticType> TYPE_MAP = {
+    { ValueType::Number, Compiler::StaticType::Number },
+    { ValueType::Bool, Compiler::StaticType::Bool },
+    { ValueType::String, Compiler::StaticType::String },
+    { ValueType::Pointer, Compiler::StaticType::Pointer }
+};
+
+LLVMBuildUtils::LLVMBuildUtils(LLVMCompilerContext *ctx, llvm::IRBuilder<> &builder) :
+    m_ctx(ctx),
+    m_llvmCtx(*ctx->llvmCtx()),
+    m_builder(builder),
+    m_functions(ctx, &builder),
+    m_target(ctx->target())
+{
+    initTypes();
+    createVariableMap();
+    createListMap();
+}
+
+void LLVMBuildUtils::init(llvm::Function *function, llvm::Value *targetVariables, llvm::Value *targetLists)
+{
+    m_function = function;
+    m_stringHeap.clear();
+    pushScopeLevel();
+
+    // Create variable pointers
+    for (auto &[var, varPtr] : m_variablePtrs) {
+        llvm::Value *ptr = getVariablePtr(targetVariables, var);
+
+        // Direct access
+        varPtr.heapPtr = ptr;
+
+        // All variables are currently created on the stack and synced later (seems to be faster)
+        // NOTE: Strings are NOT copied, only the pointer is copied
+        // TODO: Restore this feature
+        // varPtr.stackPtr = m_builder.CreateAlloca(m_valueDataType);
+        varPtr.stackPtr = varPtr.heapPtr;
+        varPtr.onStack = false;
+
+        // If there are no write operations outside loops, initialize the stack variable now
+        /*Variable *variable = var;
+        // TODO: Loop scope was used here, replace it with some "inside loop" flag if needed
+        auto it = std::find_if(m_variableInstructions.begin(), m_variableInstructions.end(), [variable](const LLVMInstruction *ins) {
+            return ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == variable && !ins->loopScope;
+        });
+
+        if (it == m_variableInstructions.end()) {
+            createValueCopy(ptr, varPtr.stackPtr);
+            varPtr.onStack = true;
+        } else
+            varPtr.onStack = false; // use heap before the first assignment
+        */
+    }
+
+    // Create list pointers
+    for (auto &[list, listPtr] : m_listPtrs) {
+        listPtr.ptr = getListPtr(targetLists, list);
+
+        listPtr.dataPtr = m_builder.CreateAlloca(m_valueDataType->getPointerTo()->getPointerTo());
+        m_builder.CreateStore(m_builder.CreateCall(m_functions.resolve_list_data_ptr(), listPtr.ptr), listPtr.dataPtr);
+
+        listPtr.sizePtr = m_builder.CreateCall(m_functions.resolve_list_size_ptr(), listPtr.ptr);
+        listPtr.allocatedSizePtr = m_builder.CreateCall(m_functions.resolve_list_alloc_size_ptr(), listPtr.ptr);
+    }
+}
+
+void LLVMBuildUtils::end()
+{
+    assert(m_stringHeap.size() == 1);
+    freeScopeHeap();
+}
+
+LLVMFunctions &LLVMBuildUtils::functions()
+{
+    return m_functions;
+}
+
+void LLVMBuildUtils::createVariablePtr(Variable *variable)
+{
+    if (m_variablePtrs.find(variable) == m_variablePtrs.cend())
+        m_variablePtrs[variable] = LLVMVariablePtr();
+}
+
+void LLVMBuildUtils::createListPtr(List *list)
+{
+    if (m_listPtrs.find(list) == m_listPtrs.cend())
+        m_listPtrs[list] = LLVMListPtr();
+}
+
+LLVMVariablePtr &LLVMBuildUtils::variablePtr(Variable *variable)
+{
+    assert(m_variablePtrs.find(variable) != m_variablePtrs.cend());
+    return m_variablePtrs[variable];
+}
+
+LLVMListPtr &LLVMBuildUtils::listPtr(List *list)
+{
+    assert(m_listPtrs.find(list) != m_listPtrs.cend());
+    return m_listPtrs[list];
+}
+
+void LLVMBuildUtils::syncVariables(llvm::Value *targetVariables)
+{
+    // Copy stack variables to the actual variables
+    for (auto &[var, varPtr] : m_variablePtrs) {
+        if (varPtr.onStack && varPtr.changed)
+            createValueCopy(varPtr.stackPtr, getVariablePtr(targetVariables, var));
+
+        varPtr.changed = false;
+    }
+}
+
+void LLVMBuildUtils::reloadVariables(llvm::Value *targetVariables)
+{
+    // Reset variables to use heap
+    for (auto &[var, varPtr] : m_variablePtrs) {
+        varPtr.onStack = false;
+        varPtr.changed = false;
+    }
+}
+
+void LLVMBuildUtils::pushScopeLevel()
+{
+    m_stringHeap.push_back({});
+}
+
+void LLVMBuildUtils::popScopeLevel()
+{
+    freeScopeHeap();
+    m_stringHeap.pop_back();
+}
+
+void LLVMBuildUtils::freeStringLater(llvm::Value *value)
+{
+    assert(!m_stringHeap.empty());
+
+    if (m_stringHeap.empty())
+        return;
+
+    m_stringHeap.back().push_back(value);
+}
+
+void LLVMBuildUtils::freeScopeHeap()
+{
+    if (m_stringHeap.empty())
+        return;
+
+    // Free strings in current scope
+    auto &heap = m_stringHeap.back();
+
+    for (llvm::Value *ptr : heap)
+        m_builder.CreateCall(m_functions.resolve_string_pool_free(), { ptr });
+
+    heap.clear();
+}
+
+Compiler::StaticType LLVMBuildUtils::optimizeRegisterType(LLVMRegister *reg)
+{
+    Compiler::StaticType ret = reg->type();
+
+    // Optimize string constants that represent numbers
+    if (reg->isConst() && reg->type() == Compiler::StaticType::String && reg->constValue().isValidNumber())
+        ret = Compiler::StaticType::Number;
+
+    return ret;
+}
+
+Compiler::StaticType LLVMBuildUtils::mapType(ValueType type)
+{
+    assert(TYPE_MAP.find(type) != TYPE_MAP.cend());
+    return TYPE_MAP[type];
+}
+
+llvm::Value *LLVMBuildUtils::addAlloca(llvm::Type *type)
+{
+    // Add an alloca to the entry block because allocas must be there (to avoid stack overflow)
+    llvm::BasicBlock *block = m_builder.GetInsertBlock();
+    m_builder.SetInsertPointPastAllocas(m_function);
+    llvm::Value *ret = m_builder.CreateAlloca(type);
+    m_builder.SetInsertPoint(block);
+    return ret;
+}
+
+llvm::Value *LLVMBuildUtils::castValue(LLVMRegister *reg, Compiler::StaticType targetType)
+{
+    if (reg->isConst()) {
+        if (targetType == Compiler::StaticType::Unknown)
+            return createValue(reg);
+        else
+            return castConstValue(reg->constValue(), targetType);
+    }
+
+    if (reg->isRawValue)
+        return castRawValue(reg, targetType);
+
+    assert(reg->type() != Compiler::StaticType::Void && targetType != Compiler::StaticType::Void);
+
+    switch (targetType) {
+        case Compiler::StaticType::Number:
+            switch (reg->type()) {
+                case Compiler::StaticType::Number: {
+                    // Read number directly
+                    llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 0);
+                    return m_builder.CreateLoad(m_builder.getDoubleTy(), ptr);
+                }
+
+                case Compiler::StaticType::Bool: {
+                    // Read boolean and cast to double
+                    llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 0);
+                    llvm::Value *boolValue = m_builder.CreateLoad(m_builder.getInt1Ty(), ptr);
+                    return m_builder.CreateSIToFP(boolValue, m_builder.getDoubleTy());
+                }
+
+                case Compiler::StaticType::String:
+                case Compiler::StaticType::Unknown: {
+                    // Convert to double
+                    return m_builder.CreateCall(m_functions.resolve_value_toDouble(), reg->value);
+                }
+
+                default:
+                    assert(false);
+                    return nullptr;
+            }
+
+        case Compiler::StaticType::Bool:
+            switch (reg->type()) {
+                case Compiler::StaticType::Number: {
+                    // True if != 0
+                    llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 0);
+                    llvm::Value *numberValue = m_builder.CreateLoad(m_builder.getDoubleTy(), ptr);
+                    return m_builder.CreateFCmpONE(numberValue, llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0)));
+                }
+
+                case Compiler::StaticType::Bool: {
+                    // Read boolean directly
+                    llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 0);
+                    return m_builder.CreateLoad(m_builder.getInt1Ty(), ptr);
+                }
+
+                case Compiler::StaticType::String:
+                case Compiler::StaticType::Unknown:
+                    // Convert to bool
+                    return m_builder.CreateCall(m_functions.resolve_value_toBool(), reg->value);
+
+                default:
+                    assert(false);
+                    return nullptr;
+            }
+
+        case Compiler::StaticType::String:
+            switch (reg->type()) {
+                case Compiler::StaticType::Number:
+                case Compiler::StaticType::Bool:
+                case Compiler::StaticType::Unknown: {
+                    // Cast to string
+                    // TODO: Use value_stringToDouble() and value_stringToBool()
+                    llvm::Value *ptr = m_builder.CreateCall(m_functions.resolve_value_toStringPtr(), reg->value);
+                    freeStringLater(ptr);
+                    return ptr;
+                }
+
+                case Compiler::StaticType::String: {
+                    // Read string pointer directly
+                    llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 0);
+                    return m_builder.CreateLoad(m_stringPtrType->getPointerTo(), ptr);
+                }
+
+                default:
+                    assert(false);
+                    return nullptr;
+            }
+
+        case Compiler::StaticType::Unknown:
+            return createValue(reg);
+
+        default:
+            assert(false);
+            return nullptr;
+    }
+}
+
+llvm::Type *LLVMBuildUtils::getType(Compiler::StaticType type)
+{
+    switch (type) {
+        case Compiler::StaticType::Void:
+            return m_builder.getVoidTy();
+
+        case Compiler::StaticType::Number:
+            return m_builder.getDoubleTy();
+
+        case Compiler::StaticType::Bool:
+            return m_builder.getInt1Ty();
+
+        case Compiler::StaticType::String:
+            return m_stringPtrType->getPointerTo();
+
+        case Compiler::StaticType::Pointer:
+            return m_builder.getVoidTy()->getPointerTo();
+
+        case Compiler::StaticType::Unknown:
+            return m_valueDataType->getPointerTo();
+
+        default:
+            assert(false);
+            return nullptr;
+    }
+}
+
+llvm::Value *LLVMBuildUtils::isNaN(llvm::Value *num)
+{
+    return m_builder.CreateFCmpUNO(num, num);
+}
+
+llvm::Value *LLVMBuildUtils::removeNaN(llvm::Value *num)
+{
+    // Replace NaN with zero
+    return m_builder.CreateSelect(isNaN(num), llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0)), num);
+}
+
+void LLVMBuildUtils::createValueStore(LLVMRegister *reg, llvm::Value *targetPtr, Compiler::StaticType sourceType, Compiler::StaticType targetType)
+{
+    llvm::Value *converted = nullptr;
+
+    if (sourceType != Compiler::StaticType::Unknown)
+        converted = castValue(reg, sourceType);
+
+    auto it = std::find_if(TYPE_MAP.begin(), TYPE_MAP.end(), [sourceType](const std::pair<ValueType, Compiler::StaticType> &pair) { return pair.second == sourceType; });
+    const ValueType mappedType = it == TYPE_MAP.cend() ? ValueType::Number : it->first; // unknown type can be ignored
+
+    switch (sourceType) {
+        case Compiler::StaticType::Number:
+            switch (targetType) {
+                case Compiler::StaticType::Number: {
+                    // Write number to number directly
+                    llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, targetPtr, 0);
+                    m_builder.CreateStore(converted, ptr);
+                    break;
+                }
+
+                case Compiler::StaticType::Bool: {
+                    // Write number to bool value directly and change type
+                    llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, targetPtr, 0);
+                    llvm::Value *typePtr = m_builder.CreateStructGEP(m_valueDataType, targetPtr, 1);
+                    m_builder.CreateStore(converted, ptr);
+                    m_builder.CreateStore(m_builder.getInt32(static_cast<uint32_t>(mappedType)), typePtr);
+                    break;
+                }
+
+                default:
+                    m_builder.CreateCall(m_functions.resolve_value_assign_double(), { targetPtr, converted });
+                    break;
+            }
+
+            break;
+
+        case Compiler::StaticType::Bool:
+            switch (targetType) {
+                case Compiler::StaticType::Number: {
+                    // Write bool to number value directly and change type
+                    llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, targetPtr, 0);
+                    m_builder.CreateStore(converted, ptr);
+                    llvm::Value *typePtr = m_builder.CreateStructGEP(m_valueDataType, targetPtr, 1);
+                    m_builder.CreateStore(converted, ptr);
+                    m_builder.CreateStore(m_builder.getInt32(static_cast<uint32_t>(mappedType)), typePtr);
+                    break;
+                }
+
+                case Compiler::StaticType::Bool: {
+                    // Write bool to bool directly
+                    llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, targetPtr, 0);
+                    m_builder.CreateStore(converted, ptr);
+                    break;
+                }
+
+                default:
+                    m_builder.CreateCall(m_functions.resolve_value_assign_bool(), { targetPtr, converted });
+                    break;
+            }
+
+            break;
+
+        case Compiler::StaticType::String:
+            m_builder.CreateCall(m_functions.resolve_value_assign_stringPtr(), { targetPtr, converted });
+            break;
+
+        case Compiler::StaticType::Unknown:
+            m_builder.CreateCall(m_functions.resolve_value_assign_copy(), { targetPtr, reg->value });
+            break;
+
+        default:
+            assert(false);
+            break;
+    }
+}
+
+void LLVMBuildUtils::createReusedValueStore(LLVMRegister *reg, llvm::Value *targetPtr, Compiler::StaticType sourceType, Compiler::StaticType targetType)
+{
+    // Same as createValueStore(), but ensures that type is updated
+    createValueStore(reg, targetPtr, sourceType, targetType);
+
+    auto it = std::find_if(TYPE_MAP.begin(), TYPE_MAP.end(), [sourceType](const std::pair<ValueType, Compiler::StaticType> &pair) { return pair.second == sourceType; });
+    const ValueType mappedType = it == TYPE_MAP.cend() ? ValueType::Number : it->first; // unknown type can be ignored
+
+    if ((sourceType == Compiler::StaticType::Number || sourceType == Compiler::StaticType::Bool) && sourceType == targetType) {
+        // Update type when writing number to number and bool to bool
+        llvm::Value *typePtr = m_builder.CreateStructGEP(m_valueDataType, targetPtr, 1);
+        m_builder.CreateStore(m_builder.getInt32(static_cast<uint32_t>(mappedType)), typePtr);
+    }
+}
+
+llvm::Value *LLVMBuildUtils::getListItem(const LLVMListPtr &listPtr, llvm::Value *index)
+{
+    return m_builder.CreateGEP(m_valueDataType, getListDataPtr(listPtr), index);
+}
+
+llvm::Value *LLVMBuildUtils::getListItemIndex(const LLVMListPtr &listPtr, Compiler::StaticType listType, LLVMRegister *item)
+{
+    llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.sizePtr);
+    llvm::BasicBlock *condBlock = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
+    llvm::BasicBlock *bodyBlock = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
+    llvm::BasicBlock *cmpIfBlock = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
+    llvm::BasicBlock *cmpElseBlock = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
+    llvm::BasicBlock *notFoundBlock = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
+    llvm::BasicBlock *nextBlock = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
+
+    // index = 0
+    llvm::Value *index = addAlloca(m_builder.getInt64Ty());
+    m_builder.CreateStore(m_builder.getInt64(0), index);
+    m_builder.CreateBr(condBlock);
+
+    // while (index < size)
+    m_builder.SetInsertPoint(condBlock);
+    llvm::Value *cond = m_builder.CreateICmpULT(m_builder.CreateLoad(m_builder.getInt64Ty(), index), size);
+    m_builder.CreateCondBr(cond, bodyBlock, notFoundBlock);
+
+    // if (list[index] == item)
+    m_builder.SetInsertPoint(bodyBlock);
+    LLVMRegister currentItem(listType);
+    currentItem.isRawValue = false;
+    currentItem.value = getListItem(listPtr, m_builder.CreateLoad(m_builder.getInt64Ty(), index));
+    llvm::Value *cmp = createComparison(&currentItem, item, Comparison::EQ);
+    m_builder.CreateCondBr(cmp, cmpIfBlock, cmpElseBlock);
+
+    // goto nextBlock
+    m_builder.SetInsertPoint(cmpIfBlock);
+    m_builder.CreateBr(nextBlock);
+
+    // else index++
+    m_builder.SetInsertPoint(cmpElseBlock);
+    m_builder.CreateStore(m_builder.CreateAdd(m_builder.CreateLoad(m_builder.getInt64Ty(), index), m_builder.getInt64(1)), index);
+    m_builder.CreateBr(condBlock);
+
+    // notFoundBlock:
+    // index = -1
+    // goto nextBlock
+    m_builder.SetInsertPoint(notFoundBlock);
+    m_builder.CreateStore(llvm::ConstantInt::get(llvm::Type::getInt64Ty(m_llvmCtx), -1, true), index);
+    m_builder.CreateBr(nextBlock);
+
+    // nextBlock:
+    m_builder.SetInsertPoint(nextBlock);
+
+    return m_builder.CreateLoad(m_builder.getInt64Ty(), index);
+}
+
+llvm::Value *LLVMBuildUtils::createValue(LLVMRegister *reg)
+{
+    if (reg->isConst()) {
+        // Create a constant ValueData instance and store it
+        llvm::Constant *value = castConstValue(reg->constValue(), TYPE_MAP[reg->constValue().type()]);
+        llvm::Value *ret = addAlloca(m_valueDataType);
+
+        switch (reg->constValue().type()) {
+            case ValueType::Number:
+                value = llvm::ConstantExpr::getBitCast(value, m_valueDataType->getElementType(0));
+                break;
+
+            case ValueType::Bool:
+                // Assuming union type is int64
+                value = m_builder.getInt64(reg->constValue().toBool());
+                break;
+
+            case ValueType::String:
+            case ValueType::Pointer:
+                value = llvm::ConstantExpr::getPtrToInt(value, m_valueDataType->getElementType(0));
+                break;
+
+            default:
+                assert(false);
+                break;
+        }
+
+        llvm::Constant *type = m_builder.getInt32(static_cast<uint32_t>(reg->constValue().type()));
+        llvm::Constant *padding = m_builder.getInt32(0);
+        llvm::Constant *constValue = llvm::ConstantStruct::get(m_valueDataType, { value, type, padding });
+        m_builder.CreateStore(constValue, ret);
+
+        return ret;
+    } else if (reg->isRawValue) {
+        llvm::Value *value = castRawValue(reg, reg->type());
+        llvm::Value *ret = addAlloca(m_valueDataType);
+
+        // Store value
+        llvm::Value *valueField = m_builder.CreateStructGEP(m_valueDataType, ret, 0);
+        m_builder.CreateStore(value, valueField);
+
+        auto it = std::find_if(TYPE_MAP.begin(), TYPE_MAP.end(), [&reg](const std::pair<ValueType, Compiler::StaticType> &pair) { return pair.second == reg->type(); });
+
+        if (it == TYPE_MAP.end()) {
+            assert(false);
+            return nullptr;
+        }
+
+        // Store type
+        llvm::Value *typeField = m_builder.CreateStructGEP(m_valueDataType, ret, 1);
+        ValueType type = it->first;
+        m_builder.CreateStore(m_builder.getInt32(static_cast<uint32_t>(type)), typeField);
+
+        return ret;
+    } else
+        return reg->value;
+}
+
+llvm::Value *LLVMBuildUtils::createNewValue(LLVMRegister *reg)
+{
+    // Same as createValue(), but creates a copy of the contents
+    // NOTE: It is the caller's responsibility to free the value.
+    llvm::Value *value = createValue(reg);
+    llvm::Value *ret = addAlloca(m_valueDataType);
+    m_builder.CreateCall(m_functions.resolve_value_init(), { ret });
+    m_builder.CreateCall(m_functions.resolve_value_assign_copy(), { ret, value });
+    return ret;
+}
+
+llvm::Value *LLVMBuildUtils::createComparison(LLVMRegister *arg1, LLVMRegister *arg2, Comparison type)
+{
+    auto type1 = arg1->type();
+    auto type2 = arg2->type();
+
+    if (arg1->isConst() && arg2->isConst()) {
+        // If both operands are constant, perform the comparison at compile time
+        bool result = false;
+
+        switch (type) {
+            case Comparison::EQ:
+                result = arg1->constValue() == arg2->constValue();
+                break;
+
+            case Comparison::GT:
+                result = arg1->constValue() > arg2->constValue();
+                break;
+
+            case Comparison::LT:
+                result = arg1->constValue() < arg2->constValue();
+                break;
+
+            default:
+                assert(false);
+                return nullptr;
+        }
+
+        return m_builder.getInt1(result);
+    } else {
+        // Optimize comparison of constant with number/bool
+        if (arg1->isConst() && arg1->constValue().isValidNumber() && (type2 == Compiler::StaticType::Number || type2 == Compiler::StaticType::Bool))
+            type1 = Compiler::StaticType::Number;
+
+        if (arg2->isConst() && arg2->constValue().isValidNumber() && (type1 == Compiler::StaticType::Number || type1 == Compiler::StaticType::Bool))
+            type2 = Compiler::StaticType::Number;
+
+        // Optimize number and bool comparison
+        int optNumberBool = 0;
+
+        if (type1 == Compiler::StaticType::Number && type2 == Compiler::StaticType::Bool) {
+            type2 = Compiler::StaticType::Number;
+            optNumberBool = 2; // operand 2 was bool
+        }
+
+        if (type1 == Compiler::StaticType::Bool && type2 == Compiler::StaticType::Number) {
+            type1 = Compiler::StaticType::Number;
+            optNumberBool = 1; // operand 1 was bool
+        }
+
+        // Optimize number and string constant comparison
+        // TODO: GT and LT comparison can be optimized here (e. g. by checking the string constant characters and comparing with numbers and .+-e)
+        if (type == Comparison::EQ) {
+            if ((type1 == Compiler::StaticType::Number && type2 == Compiler::StaticType::String && arg2->isConst() && !arg2->constValue().isValidNumber()) ||
+                (type1 == Compiler::StaticType::String && type2 == Compiler::StaticType::Number && arg1->isConst() && !arg1->constValue().isValidNumber()))
+                return m_builder.getInt1(false);
+        }
+
+        if (type1 != type2 || type1 == Compiler::StaticType::Unknown || type2 == Compiler::StaticType::Unknown) {
+            // If the types are different or at least one of them
+            // is unknown, we must use value functions
+            llvm::Value *value1 = createValue(arg1);
+            llvm::Value *value2 = createValue(arg2);
+
+            switch (type) {
+                case Comparison::EQ:
+                    return m_builder.CreateCall(m_functions.resolve_value_equals(), { value1, value2 });
+
+                case Comparison::GT:
+                    return m_builder.CreateCall(m_functions.resolve_value_greater(), { value1, value2 });
+
+                case Comparison::LT:
+                    return m_builder.CreateCall(m_functions.resolve_value_lower(), { value1, value2 });
+
+                default:
+                    assert(false);
+                    return nullptr;
+            }
+        } else {
+            // Compare raw values
+            llvm::Value *value1 = castValue(arg1, type1);
+            llvm::Value *value2 = castValue(arg2, type2);
+            assert(type1 == type2);
+
+            switch (type1) {
+                case Compiler::StaticType::Number: {
+                    // Compare two numbers
+                    switch (type) {
+                        case Comparison::EQ: {
+                            llvm::Value *nan = m_builder.CreateAnd(isNaN(value1), isNaN(value2)); // NaN == NaN
+                            llvm::Value *cmp = m_builder.CreateFCmpOEQ(value1, value2);
+                            return m_builder.CreateSelect(nan, m_builder.getInt1(true), cmp);
+                        }
+
+                        case Comparison::GT: {
+                            llvm::Value *bothNan = m_builder.CreateAnd(isNaN(value1), isNaN(value2)); // NaN == NaN
+                            llvm::Value *cmp = m_builder.CreateFCmpOGT(value1, value2);
+                            llvm::Value *nan;
+                            llvm::Value *nanCmp;
+
+                            if (optNumberBool == 1) {
+                                nan = isNaN(value2);
+                                nanCmp = castValue(arg1, Compiler::StaticType::Bool);
+                            } else if (optNumberBool == 2) {
+                                nan = isNaN(value1);
+                                nanCmp = m_builder.CreateNot(castValue(arg2, Compiler::StaticType::Bool));
+                            } else {
+                                nan = isNaN(value1);
+                                nanCmp = m_builder.CreateFCmpUGT(value1, value2);
+                            }
+
+                            return m_builder.CreateAnd(m_builder.CreateNot(bothNan), m_builder.CreateSelect(nan, nanCmp, cmp));
+                        }
+
+                        case Comparison::LT: {
+                            llvm::Value *bothNan = m_builder.CreateAnd(isNaN(value1), isNaN(value2)); // NaN == NaN
+                            llvm::Value *cmp = m_builder.CreateFCmpOLT(value1, value2);
+                            llvm::Value *nan;
+                            llvm::Value *nanCmp;
+
+                            if (optNumberBool == 1) {
+                                nan = isNaN(value2);
+                                nanCmp = m_builder.CreateNot(castValue(arg1, Compiler::StaticType::Bool));
+                            } else if (optNumberBool == 2) {
+                                nan = isNaN(value1);
+                                nanCmp = castValue(arg2, Compiler::StaticType::Bool);
+                            } else {
+                                nan = isNaN(value2);
+                                nanCmp = m_builder.CreateFCmpULT(value1, value2);
+                            }
+
+                            return m_builder.CreateAnd(m_builder.CreateNot(bothNan), m_builder.CreateSelect(nan, nanCmp, cmp));
+                        }
+
+                        default:
+                            assert(false);
+                            return nullptr;
+                    }
+                }
+
+                case Compiler::StaticType::Bool:
+                    // Compare two booleans
+                    switch (type) {
+                        case Comparison::EQ:
+                            return m_builder.CreateICmpEQ(value1, value2);
+
+                        case Comparison::GT:
+                            // value1 && !value2
+                            return m_builder.CreateAnd(value1, m_builder.CreateNot(value2));
+
+                        case Comparison::LT:
+                            // value2 && !value1
+                            return m_builder.CreateAnd(value2, m_builder.CreateNot(value1));
+
+                        default:
+                            assert(false);
+                            return nullptr;
+                    }
+
+                case Compiler::StaticType::String: {
+                    // Compare two strings
+                    llvm::Value *cmpRet = m_builder.CreateCall(m_functions.resolve_string_compare_case_insensitive(), { value1, value2 });
+
+                    switch (type) {
+                        case Comparison::EQ:
+                            return m_builder.CreateICmpEQ(cmpRet, m_builder.getInt32(0));
+
+                        case Comparison::GT:
+                            return m_builder.CreateICmpSGT(cmpRet, m_builder.getInt32(0));
+
+                        case Comparison::LT:
+                            return m_builder.CreateICmpSLT(cmpRet, m_builder.getInt32(0));
+
+                        default:
+                            assert(false);
+                            return nullptr;
+                    }
+                }
+
+                default:
+                    assert(false);
+                    return nullptr;
+            }
+        }
+    }
+}
+
+llvm::Value *LLVMBuildUtils::createStringComparison(LLVMRegister *arg1, LLVMRegister *arg2, bool caseSensitive)
+{
+    auto type1 = arg1->type();
+    auto type2 = arg2->type();
+
+    if (arg1->isConst() && arg2->isConst()) {
+        // If both operands are constant, perform the comparison at compile time
+        StringPtr *str1 = value_toStringPtr(&arg1->constValue().data());
+        StringPtr *str2 = value_toStringPtr(&arg2->constValue().data());
+        bool result;
+
+        if (caseSensitive)
+            result = string_compare_case_sensitive(str1, str2) == 0;
+        else {
+            result = string_compare_case_insensitive(str1, str2) == 0;
+        }
+
+        string_pool_free(str1);
+        string_pool_free(str2);
+        return m_builder.getInt1(result);
+    } else {
+        // Optimize number and string constant comparison
+        // TODO: Optimize bool and string constant comparison (in compare() as well)
+        if ((type1 == Compiler::StaticType::Number && type2 == Compiler::StaticType::String && arg2->isConst() && !arg2->constValue().isValidNumber()) ||
+            (type1 == Compiler::StaticType::String && type2 == Compiler::StaticType::Number && arg1->isConst() && !arg1->constValue().isValidNumber()))
+            return m_builder.getInt1(false);
+
+        // Explicitly cast to string
+        llvm::Value *string1 = castValue(arg1, Compiler::StaticType::String);
+        llvm::Value *string2 = castValue(arg2, Compiler::StaticType::String);
+        llvm::Value *cmp = m_builder.CreateCall(caseSensitive ? m_functions.resolve_string_compare_case_sensitive() : m_functions.resolve_string_compare_case_insensitive(), { string1, string2 });
+        return m_builder.CreateICmpEQ(cmp, m_builder.getInt32(0));
+    }
+}
+
+void LLVMBuildUtils::initTypes()
+{
+    m_valueDataType = m_ctx->valueDataType();
+    m_stringPtrType = m_ctx->stringPtrType();
+}
+
+void LLVMBuildUtils::createVariableMap()
+{
+    if (!m_target)
+        return;
+
+    // Map variable pointers to variable data array indices
+    const auto &variables = m_target->variables();
+    ValueData **variableData = m_target->variableData();
+    const size_t len = variables.size();
+    m_targetVariableMap.clear();
+    m_targetVariableMap.reserve(len);
+
+    size_t i, j;
+
+    for (i = 0; i < len; i++) {
+        Variable *var = variables[i].get();
+
+        // Find the data for this variable
+        for (j = 0; j < len; j++) {
+            if (variableData[j] == &var->valuePtr()->data())
+                break;
+        }
+
+        if (j < len)
+            m_targetVariableMap[var] = j;
+        else
+            assert(false);
+    }
+}
+
+void LLVMBuildUtils::createListMap()
+{
+    if (!m_target)
+        return;
+
+    // Map list pointers to list array indices
+    const auto &lists = m_target->lists();
+    List **listData = m_target->listData();
+    const size_t len = lists.size();
+    m_targetListMap.clear();
+    m_targetListMap.reserve(len);
+
+    size_t i, j;
+
+    for (i = 0; i < len; i++) {
+        List *list = lists[i].get();
+
+        // Find this list
+        for (j = 0; j < len; j++) {
+            if (listData[j] == list)
+                break;
+        }
+
+        if (j < len)
+            m_targetListMap[list] = j;
+        else
+            assert(false);
+    }
+}
+
+llvm::Value *LLVMBuildUtils::castRawValue(LLVMRegister *reg, Compiler::StaticType targetType)
+{
+    if (reg->type() == targetType)
+        return reg->value;
+
+    switch (targetType) {
+        case Compiler::StaticType::Number:
+            switch (reg->type()) {
+                case Compiler::StaticType::Bool:
+                    // Cast bool to double
+                    return m_builder.CreateUIToFP(reg->value, m_builder.getDoubleTy());
+
+                case Compiler::StaticType::String: {
+                    // Convert string to double
+                    return m_builder.CreateCall(m_functions.resolve_value_stringToDouble(), reg->value);
+                }
+
+                default:
+                    assert(false);
+                    return nullptr;
+            }
+
+        case Compiler::StaticType::Bool:
+            switch (reg->type()) {
+                case Compiler::StaticType::Number:
+                    // Cast double to bool (true if != 0)
+                    return m_builder.CreateFCmpONE(reg->value, llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0)));
+
+                case Compiler::StaticType::String:
+                    // Convert string to bool
+                    return m_builder.CreateCall(m_functions.resolve_value_stringToBool(), reg->value);
+
+                default:
+                    assert(false);
+                    return nullptr;
+            }
+
+        case Compiler::StaticType::String:
+            switch (reg->type()) {
+                case Compiler::StaticType::Number: {
+                    // Convert double to string
+                    llvm::Value *ptr = m_builder.CreateCall(m_functions.resolve_value_doubleToStringPtr(), reg->value);
+                    freeStringLater(ptr);
+                    return ptr;
+                }
+
+                case Compiler::StaticType::Bool: {
+                    // Convert bool to string
+                    llvm::Value *ptr = m_builder.CreateCall(m_functions.resolve_value_boolToStringPtr(), reg->value);
+                    // NOTE: Dot not deallocate later
+                    return ptr;
+                }
+
+                default:
+                    assert(false);
+                    return nullptr;
+            }
+
+        case Compiler::StaticType::Unknown:
+            return createValue(reg);
+
+        default:
+            assert(false);
+            return nullptr;
+    }
+}
+
+llvm::Constant *LLVMBuildUtils::castConstValue(const Value &value, Compiler::StaticType targetType)
+{
+    switch (targetType) {
+        case Compiler::StaticType::Number: {
+            const double nan = std::numeric_limits<double>::quiet_NaN();
+            return llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(value.isNaN() ? nan : value.toDouble()));
+        }
+
+        case Compiler::StaticType::Bool:
+            return m_builder.getInt1(value.toBool());
+
+        case Compiler::StaticType::String: {
+            std::u16string str = value.toUtf16();
+
+            // Create a constant array for the string
+            std::vector<llvm::Constant *> elements;
+            for (char16_t ch : str)
+                elements.push_back(m_builder.getInt16(ch));
+
+            elements.push_back(m_builder.getInt16(0)); // null terminator
+
+            llvm::ArrayType *arrayType = llvm::ArrayType::get(m_builder.getInt16Ty(), elements.size());
+            llvm::Constant *constArray = llvm::ConstantArray::get(arrayType, elements);
+
+            llvm::Module &module = *m_ctx->module();
+
+            llvm::Constant *globalStr = new llvm::GlobalVariable(module, arrayType, true, llvm::GlobalValue::PrivateLinkage, constArray, "string");
+            llvm::Constant *stringStruct = llvm::ConstantStruct::get(m_stringPtrType, { globalStr, m_builder.getInt64(str.size()), m_builder.getInt64(str.size() + 1) });
+            return new llvm::GlobalVariable(module, m_stringPtrType, true, llvm::GlobalValue::PrivateLinkage, stringStruct, "stringPtr");
+        }
+
+        case Compiler::StaticType::Pointer: {
+            llvm::Constant *addr = m_builder.getInt64((uintptr_t)value.toPointer());
+            return llvm::ConstantExpr::getIntToPtr(addr, m_builder.getVoidTy()->getPointerTo());
+        }
+
+        default:
+            assert(false);
+            return nullptr;
+    }
+}
+
+void LLVMBuildUtils::createValueCopy(llvm::Value *source, llvm::Value *target)
+{
+    // NOTE: This doesn't copy strings, but only the pointers
+    copyStructField(source, target, 0, m_valueDataType, m_builder.getInt64Ty()); // value
+    copyStructField(source, target, 1, m_valueDataType, m_builder.getInt32Ty()); // type
+    /* 2: padding */
+}
+
+void LLVMBuildUtils::copyStructField(llvm::Value *source, llvm::Value *target, int index, llvm::StructType *structType, llvm::Type *fieldType)
+{
+    llvm::Value *sourceField = m_builder.CreateStructGEP(structType, source, index);
+    llvm::Value *targetField = m_builder.CreateStructGEP(structType, target, index);
+    m_builder.CreateStore(m_builder.CreateLoad(fieldType, sourceField), targetField);
+}
+
+llvm::Value *LLVMBuildUtils::getVariablePtr(llvm::Value *targetVariables, Variable *variable)
+{
+    if (!m_target->isStage() && variable->target() == m_target) {
+        // If this is a local sprite variable, use the variable array at runtime (for clones)
+        assert(m_targetVariableMap.find(variable) != m_targetVariableMap.cend());
+        const size_t index = m_targetVariableMap[variable];
+        llvm::Value *ptr = m_builder.CreateGEP(m_valueDataType->getPointerTo(), targetVariables, m_builder.getInt64(index));
+        return m_builder.CreateLoad(m_valueDataType->getPointerTo(), ptr);
+    }
+
+    // Otherwise create a raw pointer at compile time
+    llvm::Value *addr = m_builder.getInt64((uintptr_t)&variable->value().data());
+    return m_builder.CreateIntToPtr(addr, m_valueDataType->getPointerTo());
+}
+
+llvm::Value *LLVMBuildUtils::getListPtr(llvm::Value *targetLists, List *list)
+{
+    if (!m_target->isStage() && list->target() == m_target) {
+        // If this is a local sprite list, use the list array at runtime (for clones)
+        assert(m_targetListMap.find(list) != m_targetListMap.cend());
+        const size_t index = m_targetListMap[list];
+        auto pointerType = llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0);
+        llvm::Value *ptr = m_builder.CreateGEP(pointerType, targetLists, m_builder.getInt64(index));
+        return m_builder.CreateLoad(pointerType, ptr);
+    }
+
+    // Otherwise create a raw pointer at compile time
+    llvm::Value *addr = m_builder.getInt64((uintptr_t)list);
+    return m_builder.CreateIntToPtr(addr, m_valueDataType->getPointerTo());
+}
+
+llvm::Value *LLVMBuildUtils::getListDataPtr(const LLVMListPtr &listPtr)
+{
+    return m_builder.CreateLoad(m_valueDataType->getPointerTo(), m_builder.CreateLoad(m_valueDataType->getPointerTo()->getPointerTo(), listPtr.dataPtr));
+}
diff --git a/src/engine/internal/llvm/llvmbuildutils.h b/src/engine/internal/llvm/llvmbuildutils.h
new file mode 100644
index 00000000..0a3d3f9b
--- /dev/null
+++ b/src/engine/internal/llvm/llvmbuildutils.h
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include <scratchcpp/valuedata.h>
+
+#include "llvmfunctions.h"
+#include "llvmvariableptr.h"
+#include "llvmlistptr.h"
+
+namespace libscratchcpp
+{
+
+class LLVMRegister;
+
+class LLVMBuildUtils
+{
+    public:
+        enum class Comparison
+        {
+            EQ,
+            GT,
+            LT
+        };
+
+        LLVMBuildUtils(LLVMCompilerContext *ctx, llvm::IRBuilder<> &builder);
+
+        void init(llvm::Function *function, llvm::Value *targetVariables, llvm::Value *targetLists);
+        void end();
+
+        LLVMFunctions &functions();
+
+        void createVariablePtr(Variable *variable);
+        void createListPtr(List *list);
+
+        LLVMVariablePtr &variablePtr(Variable *variable);
+        LLVMListPtr &listPtr(List *list);
+
+        void syncVariables(llvm::Value *targetVariables);
+        void reloadVariables(llvm::Value *targetVariables);
+
+        void pushScopeLevel();
+        void popScopeLevel();
+
+        void freeStringLater(llvm::Value *value);
+        void freeScopeHeap();
+
+        static Compiler::StaticType optimizeRegisterType(LLVMRegister *reg);
+        static Compiler::StaticType mapType(ValueType type);
+
+        llvm::Value *addAlloca(llvm::Type *type);
+        llvm::Value *castValue(LLVMRegister *reg, Compiler::StaticType targetType);
+        llvm::Type *getType(Compiler::StaticType type);
+        llvm::Value *isNaN(llvm::Value *num);
+        llvm::Value *removeNaN(llvm::Value *num);
+
+        void createValueStore(LLVMRegister *reg, llvm::Value *targetPtr, Compiler::StaticType sourceType, Compiler::StaticType targetType);
+        void createReusedValueStore(LLVMRegister *reg, llvm::Value *targetPtr, Compiler::StaticType sourceType, Compiler::StaticType targetType);
+
+        llvm::Value *getListItem(const LLVMListPtr &listPtr, llvm::Value *index);
+        llvm::Value *getListItemIndex(const LLVMListPtr &listPtr, Compiler::StaticType listType, LLVMRegister *item);
+        llvm::Value *createValue(LLVMRegister *reg);
+        llvm::Value *createNewValue(LLVMRegister *reg);
+        llvm::Value *createComparison(LLVMRegister *arg1, LLVMRegister *arg2, Comparison type);
+        llvm::Value *createStringComparison(LLVMRegister *arg1, LLVMRegister *arg2, bool caseSensitive);
+
+    private:
+        void initTypes();
+        void createVariableMap();
+        void createListMap();
+
+        llvm::Value *castRawValue(LLVMRegister *reg, Compiler::StaticType targetType);
+        llvm::Constant *castConstValue(const Value &value, Compiler::StaticType targetType);
+
+        void createValueCopy(llvm::Value *source, llvm::Value *target);
+        void copyStructField(llvm::Value *source, llvm::Value *target, int index, llvm::StructType *structType, llvm::Type *fieldType);
+
+        llvm::Value *getVariablePtr(llvm::Value *targetVariables, Variable *variable);
+        llvm::Value *getListPtr(llvm::Value *targetLists, List *list);
+        llvm::Value *getListDataPtr(const LLVMListPtr &listPtr);
+
+        LLVMCompilerContext *m_ctx = nullptr;
+        llvm::LLVMContext &m_llvmCtx;
+        llvm::IRBuilder<> &m_builder;
+        LLVMFunctions m_functions;
+        Target *m_target = nullptr;
+        llvm::Function *m_function = nullptr;
+
+        llvm::StructType *m_valueDataType = nullptr;
+        llvm::StructType *m_stringPtrType = nullptr;
+
+        std::unordered_map<Variable *, size_t> m_targetVariableMap;
+        std::unordered_map<Variable *, LLVMVariablePtr> m_variablePtrs;
+
+        std::unordered_map<List *, size_t> m_targetListMap;
+        std::unordered_map<List *, LLVMListPtr> m_listPtrs;
+
+        std::vector<std::vector<llvm::Value *>> m_stringHeap; // scopes
+};
+
+} // namespace libscratchcpp
diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp
index 1bc7d3e0..8516752f 100644
--- a/src/engine/internal/llvm/llvmcodebuilder.cpp
+++ b/src/engine/internal/llvm/llvmcodebuilder.cpp
@@ -18,13 +18,6 @@
 
 using namespace libscratchcpp;
 
-static std::unordered_map<ValueType, Compiler::StaticType> TYPE_MAP = {
-    { ValueType::Number, Compiler::StaticType::Number },
-    { ValueType::Bool, Compiler::StaticType::Bool },
-    { ValueType::String, Compiler::StaticType::String },
-    { ValueType::Pointer, Compiler::StaticType::Pointer }
-};
-
 static const std::unordered_set<LLVMInstruction::Type>
     VAR_LIST_READ_INSTRUCTIONS = { LLVMInstruction::Type::ReadVariable, LLVMInstruction::Type::GetListItem, LLVMInstruction::Type::GetListItemIndex, LLVMInstruction::Type::ListContainsItem };
 
@@ -34,15 +27,13 @@ LLVMCodeBuilder::LLVMCodeBuilder(LLVMCompilerContext *ctx, BlockPrototype *proce
     m_llvmCtx(*ctx->llvmCtx()),
     m_module(ctx->module()),
     m_builder(m_llvmCtx),
-    m_functions(ctx, &m_builder),
+    m_utils(ctx, m_builder),
     m_procedurePrototype(procedurePrototype),
     m_defaultWarp(procedurePrototype ? procedurePrototype->warp() : false),
     m_warp(m_defaultWarp),
     m_codeType(codeType)
 {
     initTypes();
-    createVariableMap();
-    createListMap();
 
     llvm::FunctionType *funcType = getMainFunctionType(nullptr);
     m_defaultArgCount = funcType->getNumParams();
@@ -104,49 +95,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
     std::vector<LLVMIfStatement> ifStatements;
     std::vector<LLVMLoop> loops;
-    m_stringHeap.clear();
-
-    // Create variable pointers
-    for (auto &[var, varPtr] : m_variablePtrs) {
-        llvm::Value *ptr = getVariablePtr(targetVariables, var);
-
-        // Direct access
-        varPtr.heapPtr = ptr;
-
-        // All variables are currently created on the stack and synced later (seems to be faster)
-        // NOTE: Strings are NOT copied, only the pointer is copied
-        // TODO: Restore this feature
-        // varPtr.stackPtr = m_builder.CreateAlloca(m_valueDataType);
-        varPtr.stackPtr = varPtr.heapPtr;
-        varPtr.onStack = false;
-        continue;
-
-        // If there are no write operations outside loops, initialize the stack variable now
-        Variable *variable = var;
-        // TODO: Loop scope was used here, replace it with some "inside loop" flag if needed
-        auto it = std::find_if(m_variableInstructions.begin(), m_variableInstructions.end(), [variable](const LLVMInstruction *ins) {
-            return ins->type == LLVMInstruction::Type::WriteVariable && ins->workVariable == variable /*&& !ins->loopScope*/;
-        });
-
-        if (it == m_variableInstructions.end()) {
-            createValueCopy(ptr, varPtr.stackPtr);
-            varPtr.onStack = true;
-        } else
-            varPtr.onStack = false; // use heap before the first assignment
-    }
-
-    // Create list pointers
-    for (auto &[list, listPtr] : m_listPtrs) {
-        listPtr.ptr = getListPtr(targetLists, list);
-
-        listPtr.dataPtr = m_builder.CreateAlloca(m_valueDataType->getPointerTo()->getPointerTo());
-        m_builder.CreateStore(m_builder.CreateCall(m_functions.resolve_list_data_ptr(), listPtr.ptr), listPtr.dataPtr);
-
-        listPtr.sizePtr = m_builder.CreateCall(m_functions.resolve_list_size_ptr(), listPtr.ptr);
-        listPtr.allocatedSizePtr = m_builder.CreateCall(m_functions.resolve_list_alloc_size_ptr(), listPtr.ptr);
-    }
 
-    pushScopeLevel();
+    m_utils.init(m_function, targetVariables, targetLists);
 
     // Execute recorded steps
     for (LLVMInstruction *insPtr = m_instructions.first(); insPtr; insPtr = insPtr->next) {
@@ -158,7 +108,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 std::vector<llvm::Value *> args;
 
                 // Variables must be synchronized because the function can read them
-                syncVariables(targetVariables);
+                m_utils.syncVariables(targetVariables);
 
                 // Add execution context arg
                 if (step.functionCtxArg) {
@@ -174,18 +124,18 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
                 // Args
                 for (auto &arg : step.args) {
-                    types.push_back(getType(arg.first));
-                    args.push_back(castValue(arg.second, arg.first));
+                    types.push_back(m_utils.getType(arg.first));
+                    args.push_back(m_utils.castValue(arg.second, arg.first));
                 }
 
-                llvm::Type *retType = getType(step.functionReturnReg ? step.functionReturnReg->type() : Compiler::StaticType::Void);
-                llvm::Value *ret = m_builder.CreateCall(m_functions.resolveFunction(step.functionName, llvm::FunctionType::get(retType, types, false)), args);
+                llvm::Type *retType = m_utils.getType(step.functionReturnReg ? step.functionReturnReg->type() : Compiler::StaticType::Void);
+                llvm::Value *ret = m_builder.CreateCall(m_utils.functions().resolveFunction(step.functionName, llvm::FunctionType::get(retType, types, false)), args);
 
                 if (step.functionReturnReg) {
                     step.functionReturnReg->value = ret;
 
                     if (step.functionReturnReg->type() == Compiler::StaticType::String)
-                        freeStringLater(step.functionReturnReg->value);
+                        m_utils.freeStringLater(step.functionReturnReg->value);
                 }
 
                 break;
@@ -195,8 +145,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 assert(step.args.size() == 2);
                 const auto &arg1 = step.args[0];
                 const auto &arg2 = step.args[1];
-                llvm::Value *num1 = removeNaN(castValue(arg1.second, arg1.first));
-                llvm::Value *num2 = removeNaN(castValue(arg2.second, arg2.first));
+                llvm::Value *num1 = m_utils.removeNaN(m_utils.castValue(arg1.second, arg1.first));
+                llvm::Value *num2 = m_utils.removeNaN(m_utils.castValue(arg2.second, arg2.first));
                 step.functionReturnReg->value = m_builder.CreateFAdd(num1, num2);
                 break;
             }
@@ -205,8 +155,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 assert(step.args.size() == 2);
                 const auto &arg1 = step.args[0];
                 const auto &arg2 = step.args[1];
-                llvm::Value *num1 = removeNaN(castValue(arg1.second, arg1.first));
-                llvm::Value *num2 = removeNaN(castValue(arg2.second, arg2.first));
+                llvm::Value *num1 = m_utils.removeNaN(m_utils.castValue(arg1.second, arg1.first));
+                llvm::Value *num2 = m_utils.removeNaN(m_utils.castValue(arg2.second, arg2.first));
                 step.functionReturnReg->value = m_builder.CreateFSub(num1, num2);
                 break;
             }
@@ -215,8 +165,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 assert(step.args.size() == 2);
                 const auto &arg1 = step.args[0];
                 const auto &arg2 = step.args[1];
-                llvm::Value *num1 = removeNaN(castValue(arg1.second, arg1.first));
-                llvm::Value *num2 = removeNaN(castValue(arg2.second, arg2.first));
+                llvm::Value *num1 = m_utils.removeNaN(m_utils.castValue(arg1.second, arg1.first));
+                llvm::Value *num2 = m_utils.removeNaN(m_utils.castValue(arg2.second, arg2.first));
                 step.functionReturnReg->value = m_builder.CreateFMul(num1, num2);
                 break;
             }
@@ -225,8 +175,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 assert(step.args.size() == 2);
                 const auto &arg1 = step.args[0];
                 const auto &arg2 = step.args[1];
-                llvm::Value *num1 = removeNaN(castValue(arg1.second, arg1.first));
-                llvm::Value *num2 = removeNaN(castValue(arg2.second, arg2.first));
+                llvm::Value *num1 = m_utils.removeNaN(m_utils.castValue(arg1.second, arg1.first));
+                llvm::Value *num2 = m_utils.removeNaN(m_utils.castValue(arg2.second, arg2.first));
                 step.functionReturnReg->value = m_builder.CreateFDiv(num1, num2);
                 break;
             }
@@ -239,24 +189,26 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 LLVMRegister *reg2 = arg2.second;
 
                 if (reg1->type() == Compiler::StaticType::Bool && reg2->type() == Compiler::StaticType::Bool) {
-                    llvm::Value *bool1 = castValue(arg1.second, Compiler::StaticType::Bool);
-                    llvm::Value *bool2 = castValue(arg2.second, Compiler::StaticType::Bool);
-                    step.functionReturnReg->value = m_builder.CreateCall(m_functions.resolve_llvm_random_bool(), { executionContextPtr, bool1, bool2 });
+                    llvm::Value *bool1 = m_utils.castValue(arg1.second, Compiler::StaticType::Bool);
+                    llvm::Value *bool2 = m_utils.castValue(arg2.second, Compiler::StaticType::Bool);
+                    step.functionReturnReg->value = m_builder.CreateCall(m_utils.functions().resolve_llvm_random_bool(), { executionContextPtr, bool1, bool2 });
                 } else {
                     llvm::Constant *inf = llvm::ConstantFP::getInfinity(m_builder.getDoubleTy(), false);
-                    llvm::Value *num1 = removeNaN(castValue(arg1.second, Compiler::StaticType::Number));
-                    llvm::Value *num2 = removeNaN(castValue(arg2.second, Compiler::StaticType::Number));
+                    llvm::Value *num1 = m_utils.removeNaN(m_utils.castValue(arg1.second, Compiler::StaticType::Number));
+                    llvm::Value *num2 = m_utils.removeNaN(m_utils.castValue(arg2.second, Compiler::StaticType::Number));
                     llvm::Value *sum = m_builder.CreateFAdd(num1, num2);
                     llvm::Value *sumDiv = m_builder.CreateFDiv(sum, inf);
-                    llvm::Value *isInfOrNaN = isNaN(sumDiv);
+                    llvm::Value *isInfOrNaN = m_utils.isNaN(sumDiv);
 
                     // NOTE: The random function will be called even in edge cases where it isn't needed, but they're rare, so it shouldn't be an issue
                     if (reg1->type() == Compiler::StaticType::Number && reg2->type() == Compiler::StaticType::Number)
-                        step.functionReturnReg->value = m_builder.CreateSelect(isInfOrNaN, sum, m_builder.CreateCall(m_functions.resolve_llvm_random_double(), { executionContextPtr, num1, num2 }));
+                        step.functionReturnReg->value =
+                            m_builder.CreateSelect(isInfOrNaN, sum, m_builder.CreateCall(m_utils.functions().resolve_llvm_random_double(), { executionContextPtr, num1, num2 }));
                     else {
-                        llvm::Value *value1 = createValue(reg1);
-                        llvm::Value *value2 = createValue(reg2);
-                        step.functionReturnReg->value = m_builder.CreateSelect(isInfOrNaN, sum, m_builder.CreateCall(m_functions.resolve_llvm_random(), { executionContextPtr, value1, value2 }));
+                        llvm::Value *value1 = m_utils.createValue(reg1);
+                        llvm::Value *value2 = m_utils.createValue(reg2);
+                        step.functionReturnReg->value =
+                            m_builder.CreateSelect(isInfOrNaN, sum, m_builder.CreateCall(m_utils.functions().resolve_llvm_random(), { executionContextPtr, value1, value2 }));
                     }
                 }
 
@@ -267,9 +219,9 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 assert(step.args.size() == 2);
                 const auto &arg1 = step.args[0];
                 const auto &arg2 = step.args[1];
-                llvm::Value *from = m_builder.CreateFPToSI(castValue(arg1.second, arg1.first), m_builder.getInt64Ty());
-                llvm::Value *to = m_builder.CreateFPToSI(castValue(arg2.second, arg2.first), m_builder.getInt64Ty());
-                step.functionReturnReg->value = m_builder.CreateCall(m_functions.resolve_llvm_random_long(), { executionContextPtr, from, to });
+                llvm::Value *from = m_builder.CreateFPToSI(m_utils.castValue(arg1.second, arg1.first), m_builder.getInt64Ty());
+                llvm::Value *to = m_builder.CreateFPToSI(m_utils.castValue(arg2.second, arg2.first), m_builder.getInt64Ty());
+                step.functionReturnReg->value = m_builder.CreateCall(m_utils.functions().resolve_llvm_random_long(), { executionContextPtr, from, to });
                 break;
             }
 
@@ -277,7 +229,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 assert(step.args.size() == 2);
                 const auto &arg1 = step.args[0].second;
                 const auto &arg2 = step.args[1].second;
-                step.functionReturnReg->value = createComparison(arg1, arg2, Comparison::EQ);
+                step.functionReturnReg->value = m_utils.createComparison(arg1, arg2, LLVMBuildUtils::Comparison::EQ);
                 break;
             }
 
@@ -285,7 +237,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 assert(step.args.size() == 2);
                 const auto &arg1 = step.args[0].second;
                 const auto &arg2 = step.args[1].second;
-                step.functionReturnReg->value = createComparison(arg1, arg2, Comparison::GT);
+                step.functionReturnReg->value = m_utils.createComparison(arg1, arg2, LLVMBuildUtils::Comparison::GT);
                 break;
             }
 
@@ -293,7 +245,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 assert(step.args.size() == 2);
                 const auto &arg1 = step.args[0].second;
                 const auto &arg2 = step.args[1].second;
-                step.functionReturnReg->value = createComparison(arg1, arg2, Comparison::LT);
+                step.functionReturnReg->value = m_utils.createComparison(arg1, arg2, LLVMBuildUtils::Comparison::LT);
                 break;
             }
 
@@ -301,7 +253,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 assert(step.args.size() == 2);
                 const auto &arg1 = step.args[0].second;
                 const auto &arg2 = step.args[1].second;
-                step.functionReturnReg->value = createStringComparison(arg1, arg2, true);
+                step.functionReturnReg->value = m_utils.createStringComparison(arg1, arg2, true);
                 break;
             }
 
@@ -309,7 +261,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 assert(step.args.size() == 2);
                 const auto &arg1 = step.args[0].second;
                 const auto &arg2 = step.args[1].second;
-                step.functionReturnReg->value = createStringComparison(arg1, arg2, false);
+                step.functionReturnReg->value = m_utils.createStringComparison(arg1, arg2, false);
                 break;
             }
 
@@ -317,8 +269,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 assert(step.args.size() == 2);
                 const auto &arg1 = step.args[0];
                 const auto &arg2 = step.args[1];
-                llvm::Value *bool1 = castValue(arg1.second, arg1.first);
-                llvm::Value *bool2 = castValue(arg2.second, arg2.first);
+                llvm::Value *bool1 = m_utils.castValue(arg1.second, arg1.first);
+                llvm::Value *bool2 = m_utils.castValue(arg2.second, arg2.first);
                 step.functionReturnReg->value = m_builder.CreateAnd(bool1, bool2);
                 break;
             }
@@ -327,8 +279,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 assert(step.args.size() == 2);
                 const auto &arg1 = step.args[0];
                 const auto &arg2 = step.args[1];
-                llvm::Value *bool1 = castValue(arg1.second, arg1.first);
-                llvm::Value *bool2 = castValue(arg2.second, arg2.first);
+                llvm::Value *bool1 = m_utils.castValue(arg1.second, arg1.first);
+                llvm::Value *bool2 = m_utils.castValue(arg2.second, arg2.first);
                 step.functionReturnReg->value = m_builder.CreateOr(bool1, bool2);
                 break;
             }
@@ -336,7 +288,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
             case LLVMInstruction::Type::Not: {
                 assert(step.args.size() == 1);
                 const auto &arg = step.args[0];
-                llvm::Value *value = castValue(arg.second, arg.first);
+                llvm::Value *value = m_utils.castValue(arg.second, arg.first);
                 step.functionReturnReg->value = m_builder.CreateNot(value);
                 break;
             }
@@ -347,8 +299,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 const auto &arg2 = step.args[1];
                 // rem(a, b) / b < 0.0 ? rem(a, b) + b : rem(a, b)
                 llvm::Constant *zero = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0));
-                llvm::Value *num1 = removeNaN(castValue(arg1.second, arg1.first));
-                llvm::Value *num2 = removeNaN(castValue(arg2.second, arg2.first));
+                llvm::Value *num1 = m_utils.removeNaN(m_utils.castValue(arg1.second, arg1.first));
+                llvm::Value *num2 = m_utils.removeNaN(m_utils.castValue(arg2.second, arg2.first));
                 llvm::Value *value = m_builder.CreateFRem(num1, num2);                                // rem(a, b)
                 llvm::Value *cond = m_builder.CreateFCmpOLT(m_builder.CreateFDiv(value, num2), zero); // rem(a, b) / b < 0.0                                                            // rem(a, b)
                 step.functionReturnReg->value = m_builder.CreateSelect(cond, m_builder.CreateFAdd(value, num2), value);
@@ -363,7 +315,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Constant *negativeZero = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(-0.0));
                 llvm::Function *roundFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::round, m_builder.getDoubleTy());
                 llvm::Function *floorFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::floor, m_builder.getDoubleTy());
-                llvm::Value *num = removeNaN(castValue(arg.second, arg.first));
+                llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
                 llvm::Value *notNegative = m_builder.CreateFCmpOGE(num, zero);                                                                                 // num >= 0.0
                 llvm::Value *roundNum = m_builder.CreateCall(roundFunc, num);                                                                                  // round(num)
                 llvm::Value *negativeCond = m_builder.CreateFCmpOGE(num, llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(-0.5)));                               // num >= -0.5
@@ -376,7 +328,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 assert(step.args.size() == 1);
                 const auto &arg = step.args[0];
                 llvm::Function *absFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::fabs, m_builder.getDoubleTy());
-                llvm::Value *num = removeNaN(castValue(arg.second, arg.first));
+                llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
                 step.functionReturnReg->value = m_builder.CreateCall(absFunc, num);
                 break;
             }
@@ -385,7 +337,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 assert(step.args.size() == 1);
                 const auto &arg = step.args[0];
                 llvm::Function *floorFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::floor, m_builder.getDoubleTy());
-                llvm::Value *num = removeNaN(castValue(arg.second, arg.first));
+                llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
                 step.functionReturnReg->value = m_builder.CreateCall(floorFunc, num);
                 break;
             }
@@ -394,7 +346,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 assert(step.args.size() == 1);
                 const auto &arg = step.args[0];
                 llvm::Function *ceilFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::ceil, m_builder.getDoubleTy());
-                llvm::Value *num = removeNaN(castValue(arg.second, arg.first));
+                llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
                 step.functionReturnReg->value = m_builder.CreateCall(ceilFunc, num);
                 break;
             }
@@ -406,7 +358,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 // This avoids negative zero
                 llvm::Constant *zero = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0));
                 llvm::Function *sqrtFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::sqrt, m_builder.getDoubleTy());
-                llvm::Value *num = removeNaN(castValue(arg.second, arg.first));
+                llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
                 step.functionReturnReg->value = m_builder.CreateFAdd(m_builder.CreateCall(sqrtFunc, num), zero);
                 break;
             }
@@ -422,7 +374,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Constant *factor = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(1e10));
                 llvm::Function *sinFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::sin, m_builder.getDoubleTy());
                 llvm::Function *roundFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::round, m_builder.getDoubleTy());
-                llvm::Value *num = removeNaN(castValue(arg.second, arg.first));
+                llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
                 llvm::Value *sinResult = m_builder.CreateCall(sinFunc, m_builder.CreateFDiv(m_builder.CreateFMul(num, pi), piDeg)); // sin(x * pi / 180)
                 llvm::Value *rounded = m_builder.CreateCall(roundFunc, m_builder.CreateFMul(sinResult, factor));                    // round(sin(x * 180) * 1e10)
                 step.functionReturnReg->value = m_builder.CreateFAdd(m_builder.CreateFDiv(rounded, factor), zero);
@@ -438,7 +390,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Constant *factor = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(1e10));
                 llvm::Function *cosFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::cos, m_builder.getDoubleTy());
                 llvm::Function *roundFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::round, m_builder.getDoubleTy());
-                llvm::Value *num = removeNaN(castValue(arg.second, arg.first));
+                llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
                 llvm::Value *cosResult = m_builder.CreateCall(cosFunc, m_builder.CreateFDiv(m_builder.CreateFMul(num, pi), piDeg)); // cos(x * pi / 180)
                 llvm::Value *rounded = m_builder.CreateCall(roundFunc, m_builder.CreateFMul(cosResult, factor));                    // round(cos(x * 180) * 1e10)
                 step.functionReturnReg->value = m_builder.CreateFDiv(rounded, factor);
@@ -463,7 +415,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Constant *factor = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(1e10));
                 llvm::Function *tanFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::tan, m_builder.getDoubleTy());
                 llvm::Function *roundFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::round, m_builder.getDoubleTy());
-                llvm::Value *num = removeNaN(castValue(arg.second, arg.first));
+                llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
                 llvm::Value *mod = m_builder.CreateFRem(num, full);
                 llvm::Value *isUndefined1 = m_builder.CreateFCmpOEQ(mod, undefined1);                                               // rem(x, 360.0) == -270.0
                 llvm::Value *isUndefined2 = m_builder.CreateFCmpOEQ(mod, undefined2);                                               // rem(x, 360.0) == 90.0
@@ -486,7 +438,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Constant *pi = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(std::acos(-1.0)));
                 llvm::Constant *piDeg = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(180.0));
                 llvm::Function *asinFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::asin, m_builder.getDoubleTy());
-                llvm::Value *num = removeNaN(castValue(arg.second, arg.first));
+                llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
                 step.functionReturnReg->value = m_builder.CreateFAdd(m_builder.CreateFDiv(m_builder.CreateFMul(m_builder.CreateCall(asinFunc, num), piDeg), pi), zero);
                 break;
             }
@@ -498,7 +450,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Constant *pi = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(std::acos(-1.0)));
                 llvm::Constant *piDeg = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(180.0));
                 llvm::Function *acosFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::acos, m_builder.getDoubleTy());
-                llvm::Value *num = removeNaN(castValue(arg.second, arg.first));
+                llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
                 step.functionReturnReg->value = m_builder.CreateFDiv(m_builder.CreateFMul(m_builder.CreateCall(acosFunc, num), piDeg), pi);
                 break;
             }
@@ -510,7 +462,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Constant *pi = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(std::acos(-1.0)));
                 llvm::Constant *piDeg = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(180.0));
                 llvm::Function *atanFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::atan, m_builder.getDoubleTy());
-                llvm::Value *num = removeNaN(castValue(arg.second, arg.first));
+                llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
                 step.functionReturnReg->value = m_builder.CreateFDiv(m_builder.CreateFMul(m_builder.CreateCall(atanFunc, num), piDeg), pi);
                 break;
             }
@@ -520,7 +472,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 const auto &arg = step.args[0];
                 // log(x)
                 llvm::Function *logFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::log, m_builder.getDoubleTy());
-                llvm::Value *num = removeNaN(castValue(arg.second, arg.first));
+                llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
                 step.functionReturnReg->value = m_builder.CreateCall(logFunc, num);
                 break;
             }
@@ -530,7 +482,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 const auto &arg = step.args[0];
                 // log10(x)
                 llvm::Function *log10Func = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::log10, m_builder.getDoubleTy());
-                llvm::Value *num = removeNaN(castValue(arg.second, arg.first));
+                llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
                 step.functionReturnReg->value = m_builder.CreateCall(log10Func, num);
                 break;
             }
@@ -540,7 +492,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 const auto &arg = step.args[0];
                 // exp(x)
                 llvm::Function *expFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::exp, m_builder.getDoubleTy());
-                llvm::Value *num = removeNaN(castValue(arg.second, arg.first));
+                llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
                 step.functionReturnReg->value = m_builder.CreateCall(expFunc, num);
                 break;
             }
@@ -550,7 +502,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 const auto &arg = step.args[0];
                 // exp10(x)
                 llvm::Function *expFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::exp10, m_builder.getDoubleTy());
-                llvm::Value *num = removeNaN(castValue(arg.second, arg.first));
+                llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
                 step.functionReturnReg->value = m_builder.CreateCall(expFunc, num);
                 break;
             }
@@ -559,14 +511,14 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 assert(step.args.size() == 2);
                 const auto &arg1 = step.args[0];
                 const auto &arg2 = step.args[1];
-                llvm::Value *str1 = castValue(arg1.second, arg1.first);
-                llvm::Value *str2 = castValue(arg2.second, arg2.first);
+                llvm::Value *str1 = m_utils.castValue(arg1.second, arg1.first);
+                llvm::Value *str2 = m_utils.castValue(arg2.second, arg2.first);
                 llvm::PointerType *charPointerType = m_builder.getInt16Ty()->getPointerTo();
                 llvm::Function *memcpyFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::memcpy_inline, { charPointerType, charPointerType, m_builder.getInt64Ty() });
 
                 // StringPtr *result = string_pool_new(true)
-                llvm::Value *result = m_builder.CreateCall(m_functions.resolve_string_pool_new(), m_builder.getInt1(true));
-                freeStringLater(result);
+                llvm::Value *result = m_builder.CreateCall(m_utils.functions().resolve_string_pool_new(), m_builder.getInt1(true));
+                m_utils.freeStringLater(result);
 
                 // result->size = string1->size + string2->size
                 llvm::Value *sizeField1 = m_builder.CreateStructGEP(m_stringPtrType, str1, 1);
@@ -578,7 +530,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 m_builder.CreateStore(resultSize, resultSizeField);
 
                 // string_alloc(result, result->size)
-                m_builder.CreateCall(m_functions.resolve_string_alloc(), { result, resultSize });
+                m_builder.CreateCall(m_utils.functions().resolve_string_alloc(), { result, resultSize });
 
                 // memcpy(result->data, string1->data, string1->size * sizeof(char16_t))
                 llvm::Value *dataField1 = m_builder.CreateStructGEP(m_stringPtrType, str1, 0);
@@ -602,8 +554,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 assert(step.args.size() == 2);
                 const auto &arg1 = step.args[0];
                 const auto &arg2 = step.args[1];
-                llvm::Value *str = castValue(arg1.second, arg1.first);
-                llvm::Value *index = m_builder.CreateFPToSI(castValue(arg2.second, arg2.first), m_builder.getInt64Ty());
+                llvm::Value *str = m_utils.castValue(arg1.second, arg1.first);
+                llvm::Value *index = m_builder.CreateFPToSI(m_utils.castValue(arg2.second, arg2.first), m_builder.getInt64Ty());
                 llvm::PointerType *charPointerType = m_builder.getInt16Ty()->getPointerTo();
 
                 // Get data ptr and size
@@ -617,9 +569,9 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Value *charPtr = m_builder.CreateGEP(m_builder.getInt16Ty(), data, index);
 
                 // Allocate string
-                llvm::Value *result = m_builder.CreateCall(m_functions.resolve_string_pool_new(), m_builder.getInt1(true));
-                freeStringLater(result);
-                m_builder.CreateCall(m_functions.resolve_string_alloc(), { result, m_builder.getInt64(1) }); // size 1 to avoid branching
+                llvm::Value *result = m_builder.CreateCall(m_utils.functions().resolve_string_pool_new(), m_builder.getInt1(true));
+                m_utils.freeStringLater(result);
+                m_builder.CreateCall(m_utils.functions().resolve_string_alloc(), { result, m_builder.getInt64(1) }); // size 1 to avoid branching
 
                 // Get result data ptr
                 dataField = m_builder.CreateStructGEP(m_stringPtrType, result, 0);
@@ -640,7 +592,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
             case LLVMInstruction::Type::StringLength: {
                 assert(step.args.size() == 1);
                 const auto &arg = step.args[0];
-                llvm::Value *str = castValue(arg.second, arg.first);
+                llvm::Value *str = m_utils.castValue(arg.second, arg.first);
                 llvm::Value *sizeField = m_builder.CreateStructGEP(m_stringPtrType, str, 1);
                 llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), sizeField);
                 step.functionReturnReg->value = m_builder.CreateSIToFP(size, m_builder.getDoubleTy());
@@ -653,16 +605,16 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 const auto &arg2 = step.args[1];
                 const auto &arg3 = step.args[2];
                 auto type = arg2.first;
-                llvm::Value *cond = castValue(arg1.second, arg1.first);
+                llvm::Value *cond = m_utils.castValue(arg1.second, arg1.first);
                 llvm::Value *trueValue;
                 llvm::Value *falseValue;
 
                 if (type == Compiler::StaticType::Unknown) {
-                    trueValue = createValue(arg2.second);
-                    falseValue = createValue(arg3.second);
+                    trueValue = m_utils.createValue(arg2.second);
+                    falseValue = m_utils.createValue(arg3.second);
                 } else {
-                    trueValue = castValue(arg2.second, type);
-                    falseValue = castValue(arg3.second, type);
+                    trueValue = m_utils.castValue(arg2.second, type);
+                    falseValue = m_utils.castValue(arg3.second, type);
                 }
 
                 step.functionReturnReg->value = m_builder.CreateSelect(cond, trueValue, falseValue);
@@ -695,7 +647,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                         break;
                 }
 
-                step.functionReturnReg->value = addAlloca(type);
+                step.functionReturnReg->value = m_utils.addAlloca(type);
                 break;
             }
 
@@ -703,7 +655,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 assert(step.args.size() == 2);
                 const auto &arg1 = step.args[0];
                 const auto &arg2 = step.args[1];
-                llvm::Value *converted = castValue(arg2.second, arg2.first);
+                llvm::Value *converted = m_utils.castValue(arg2.second, arg2.first);
                 m_builder.CreateStore(converted, arg1.second->value);
                 break;
             }
@@ -733,10 +685,9 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
             case LLVMInstruction::Type::WriteVariable: {
                 assert(step.args.size() == 1);
-                assert(m_variablePtrs.find(step.workVariable) != m_variablePtrs.cend());
                 const auto &arg = step.args[0];
-                Compiler::StaticType argType = optimizeRegisterType(arg.second);
-                LLVMVariablePtr &varPtr = m_variablePtrs[step.workVariable];
+                Compiler::StaticType argType = m_utils.optimizeRegisterType(arg.second);
+                LLVMVariablePtr &varPtr = m_utils.variablePtr(step.workVariable);
                 varPtr.changed = true; // TODO: Handle loops and if statements
 
                 Compiler::StaticType varType = Compiler::StaticType::Unknown;
@@ -765,13 +716,13 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                     m_builder.CreateStore(m_builder.getInt32(static_cast<uint32_t>(mappedType)), typeField);
                 }*/
 
-                createValueStore(arg.second, varPtr.stackPtr, argType, varType);
+                m_utils.createValueStore(arg.second, varPtr.stackPtr, argType, varType);
                 break;
             }
 
             case LLVMInstruction::Type::ReadVariable: {
                 assert(step.args.size() == 0);
-                LLVMVariablePtr &varPtr = m_variablePtrs[step.workVariable];
+                LLVMVariablePtr &varPtr = m_utils.variablePtr(step.workVariable);
                 Compiler::StaticType type = Compiler::StaticType::Unknown;
 
                 if (m_warp)
@@ -784,21 +735,21 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
             case LLVMInstruction::Type::ClearList: {
                 assert(step.args.size() == 0);
-                LLVMListPtr &listPtr = m_listPtrs[step.workList];
-                m_builder.CreateCall(m_functions.resolve_list_clear(), listPtr.ptr);
+                LLVMListPtr &listPtr = m_utils.listPtr(step.workList);
+                m_builder.CreateCall(m_utils.functions().resolve_list_clear(), listPtr.ptr);
                 break;
             }
 
             case LLVMInstruction::Type::RemoveListItem: {
                 assert(step.args.size() == 1);
                 const auto &arg = step.args[0];
-                LLVMListPtr &listPtr = m_listPtrs[step.workList];
+                LLVMListPtr &listPtr = m_utils.listPtr(step.workList);
 
                 // Range check
                 llvm::Value *min = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0));
                 llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.sizePtr);
                 size = m_builder.CreateUIToFP(size, m_builder.getDoubleTy());
-                llvm::Value *index = castValue(arg.second, arg.first);
+                llvm::Value *index = m_utils.castValue(arg.second, arg.first);
                 llvm::Value *inRange = m_builder.CreateAnd(m_builder.CreateFCmpOGE(index, min), m_builder.CreateFCmpOLT(index, size));
                 llvm::BasicBlock *removeBlock = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
                 llvm::BasicBlock *nextBlock = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
@@ -806,8 +757,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
                 // Remove
                 m_builder.SetInsertPoint(removeBlock);
-                index = m_builder.CreateFPToUI(castValue(arg.second, arg.first), m_builder.getInt64Ty());
-                m_builder.CreateCall(m_functions.resolve_list_remove(), { listPtr.ptr, index });
+                index = m_builder.CreateFPToUI(m_utils.castValue(arg.second, arg.first), m_builder.getInt64Ty());
+                m_builder.CreateCall(m_utils.functions().resolve_list_remove(), { listPtr.ptr, index });
                 m_builder.CreateBr(nextBlock);
 
                 m_builder.SetInsertPoint(nextBlock);
@@ -817,8 +768,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
             case LLVMInstruction::Type::AppendToList: {
                 assert(step.args.size() == 1);
                 const auto &arg = step.args[0];
-                Compiler::StaticType type = optimizeRegisterType(arg.second);
-                LLVMListPtr &listPtr = m_listPtrs[step.workList];
+                Compiler::StaticType type = m_utils.optimizeRegisterType(arg.second);
+                LLVMListPtr &listPtr = m_utils.listPtr(step.workList);
 
                 Compiler::StaticType listType = Compiler::StaticType::Unknown;
 
@@ -836,15 +787,15 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
                 // If there's enough space, use the allocated memory
                 m_builder.SetInsertPoint(ifBlock);
-                llvm::Value *itemPtr = getListItem(listPtr, size);
-                createReusedValueStore(arg.second, itemPtr, type, listType);
+                llvm::Value *itemPtr = m_utils.getListItem(listPtr, size);
+                m_utils.createReusedValueStore(arg.second, itemPtr, type, listType);
                 m_builder.CreateStore(m_builder.CreateAdd(size, m_builder.getInt64(1)), listPtr.sizePtr);
                 m_builder.CreateBr(nextBlock);
 
                 // Otherwise call appendEmpty()
                 m_builder.SetInsertPoint(elseBlock);
-                itemPtr = m_builder.CreateCall(m_functions.resolve_list_append_empty(), listPtr.ptr);
-                createReusedValueStore(arg.second, itemPtr, type, listType);
+                itemPtr = m_builder.CreateCall(m_utils.functions().resolve_list_append_empty(), listPtr.ptr);
+                m_utils.createReusedValueStore(arg.second, itemPtr, type, listType);
                 m_builder.CreateBr(nextBlock);
 
                 m_builder.SetInsertPoint(nextBlock);
@@ -856,8 +807,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 assert(step.args.size() == 2);
                 const auto &indexArg = step.args[0];
                 const auto &valueArg = step.args[1];
-                Compiler::StaticType type = optimizeRegisterType(valueArg.second);
-                LLVMListPtr &listPtr = m_listPtrs[step.workList];
+                Compiler::StaticType type = m_utils.optimizeRegisterType(valueArg.second);
+                LLVMListPtr &listPtr = m_utils.listPtr(step.workList);
 
                 Compiler::StaticType listType = Compiler::StaticType::Unknown;
 
@@ -868,7 +819,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.sizePtr);
                 llvm::Value *min = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0));
                 size = m_builder.CreateUIToFP(size, m_builder.getDoubleTy());
-                llvm::Value *index = castValue(indexArg.second, indexArg.first);
+                llvm::Value *index = m_utils.castValue(indexArg.second, indexArg.first);
                 llvm::Value *inRange = m_builder.CreateAnd(m_builder.CreateFCmpOGE(index, min), m_builder.CreateFCmpOLE(index, size));
                 llvm::BasicBlock *insertBlock = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
                 llvm::BasicBlock *nextBlock = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
@@ -877,8 +828,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 // Insert
                 m_builder.SetInsertPoint(insertBlock);
                 index = m_builder.CreateFPToUI(index, m_builder.getInt64Ty());
-                llvm::Value *itemPtr = m_builder.CreateCall(m_functions.resolve_list_insert_empty(), { listPtr.ptr, index });
-                createReusedValueStore(valueArg.second, itemPtr, type, listType);
+                llvm::Value *itemPtr = m_builder.CreateCall(m_utils.functions().resolve_list_insert_empty(), { listPtr.ptr, index });
+                m_utils.createReusedValueStore(valueArg.second, itemPtr, type, listType);
 
                 m_builder.CreateBr(nextBlock);
 
@@ -890,8 +841,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 assert(step.args.size() == 2);
                 const auto &indexArg = step.args[0];
                 const auto &valueArg = step.args[1];
-                Compiler::StaticType type = optimizeRegisterType(valueArg.second);
-                LLVMListPtr &listPtr = m_listPtrs[step.workList];
+                Compiler::StaticType type = m_utils.optimizeRegisterType(valueArg.second);
+                LLVMListPtr &listPtr = m_utils.listPtr(step.workList);
 
                 Compiler::StaticType listType = Compiler::StaticType::Unknown;
 
@@ -902,7 +853,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Value *min = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0));
                 llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.sizePtr);
                 size = m_builder.CreateUIToFP(size, m_builder.getDoubleTy());
-                llvm::Value *index = castValue(indexArg.second, indexArg.first);
+                llvm::Value *index = m_utils.castValue(indexArg.second, indexArg.first);
                 llvm::Value *inRange = m_builder.CreateAnd(m_builder.CreateFCmpOGE(index, min), m_builder.CreateFCmpOLT(index, size));
                 llvm::BasicBlock *replaceBlock = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
                 llvm::BasicBlock *nextBlock = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
@@ -911,8 +862,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 // Replace
                 m_builder.SetInsertPoint(replaceBlock);
                 index = m_builder.CreateFPToUI(index, m_builder.getInt64Ty());
-                llvm::Value *itemPtr = getListItem(listPtr, index);
-                createValueStore(valueArg.second, itemPtr, type, listType);
+                llvm::Value *itemPtr = m_utils.getListItem(listPtr, index);
+                m_utils.createValueStore(valueArg.second, itemPtr, type, listType);
                 m_builder.CreateBr(nextBlock);
 
                 m_builder.SetInsertPoint(nextBlock);
@@ -921,9 +872,9 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
             case LLVMInstruction::Type::GetListContents: {
                 assert(step.args.size() == 0);
-                const LLVMListPtr &listPtr = m_listPtrs[step.workList];
-                llvm::Value *ptr = m_builder.CreateCall(m_functions.resolve_list_to_string(), listPtr.ptr);
-                freeStringLater(ptr);
+                const LLVMListPtr &listPtr = m_utils.listPtr(step.workList);
+                llvm::Value *ptr = m_builder.CreateCall(m_utils.functions().resolve_list_to_string(), listPtr.ptr);
+                m_utils.freeStringLater(ptr);
                 step.functionReturnReg->value = ptr;
                 break;
             }
@@ -931,7 +882,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
             case LLVMInstruction::Type::GetListItem: {
                 assert(step.args.size() == 1);
                 const auto &arg = step.args[0];
-                LLVMListPtr &listPtr = m_listPtrs[step.workList];
+                LLVMListPtr &listPtr = m_utils.listPtr(step.workList);
 
                 Compiler::StaticType listType = Compiler::StaticType::Unknown;
 
@@ -941,21 +892,21 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Value *min = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0));
                 llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.sizePtr);
                 size = m_builder.CreateUIToFP(size, m_builder.getDoubleTy());
-                llvm::Value *index = castValue(arg.second, arg.first);
+                llvm::Value *index = m_utils.castValue(arg.second, arg.first);
                 llvm::Value *inRange = m_builder.CreateAnd(m_builder.CreateFCmpOGE(index, min), m_builder.CreateFCmpOLT(index, size));
 
                 LLVMConstantRegister nullReg(listType == Compiler::StaticType::Unknown ? Compiler::StaticType::Number : listType, Value());
-                llvm::Value *null = createValue(static_cast<LLVMRegister *>(&nullReg));
+                llvm::Value *null = m_utils.createValue(static_cast<LLVMRegister *>(&nullReg));
 
                 index = m_builder.CreateFPToUI(index, m_builder.getInt64Ty());
-                step.functionReturnReg->value = m_builder.CreateSelect(inRange, getListItem(listPtr, index), null);
+                step.functionReturnReg->value = m_builder.CreateSelect(inRange, m_utils.getListItem(listPtr, index), null);
                 step.functionReturnReg->setType(listType);
                 break;
             }
 
             case LLVMInstruction::Type::GetListSize: {
                 assert(step.args.size() == 0);
-                const LLVMListPtr &listPtr = m_listPtrs[step.workList];
+                const LLVMListPtr &listPtr = m_utils.listPtr(step.workList);
                 llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.sizePtr);
                 step.functionReturnReg->value = m_builder.CreateUIToFP(size, m_builder.getDoubleTy());
                 break;
@@ -964,28 +915,28 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
             case LLVMInstruction::Type::GetListItemIndex: {
                 assert(step.args.size() == 1);
                 const auto &arg = step.args[0];
-                LLVMListPtr &listPtr = m_listPtrs[step.workList];
+                LLVMListPtr &listPtr = m_utils.listPtr(step.workList);
 
                 Compiler::StaticType listType = Compiler::StaticType::Unknown;
 
                 if (m_warp)
                     listType = m_typeAnalyzer.listType(step.workList, &step, Compiler::StaticType::Unknown, false);
 
-                step.functionReturnReg->value = m_builder.CreateSIToFP(getListItemIndex(listPtr, listType, arg.second), m_builder.getDoubleTy());
+                step.functionReturnReg->value = m_builder.CreateSIToFP(m_utils.getListItemIndex(listPtr, listType, arg.second), m_builder.getDoubleTy());
                 break;
             }
 
             case LLVMInstruction::Type::ListContainsItem: {
                 assert(step.args.size() == 1);
                 const auto &arg = step.args[0];
-                LLVMListPtr &listPtr = m_listPtrs[step.workList];
+                LLVMListPtr &listPtr = m_utils.listPtr(step.workList);
 
                 Compiler::StaticType listType = Compiler::StaticType::Unknown;
 
                 if (m_warp)
                     listType = m_typeAnalyzer.listType(step.workList, &step, Compiler::StaticType::Unknown, false);
 
-                llvm::Value *index = getListItemIndex(listPtr, listType, arg.second);
+                llvm::Value *index = m_utils.getListItemIndex(listPtr, listType, arg.second);
                 step.functionReturnReg->value = m_builder.CreateICmpSGT(index, llvm::ConstantInt::get(m_builder.getInt64Ty(), -1, true));
                 break;
             }
@@ -1003,13 +954,13 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 assert(step.args.size() == 1);
                 const auto &reg = step.args[0];
                 assert(reg.first == Compiler::StaticType::Bool);
-                statement.condition = castValue(reg.second, reg.first);
+                statement.condition = m_utils.castValue(reg.second, reg.first);
 
                 // Switch to body branch
                 m_builder.SetInsertPoint(statement.body);
 
                 ifStatements.push_back(statement);
-                pushScopeLevel();
+                m_utils.pushScopeLevel();
                 break;
             }
 
@@ -1020,7 +971,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 // Jump to the branch after the if statement
                 assert(!statement.afterIf);
                 statement.afterIf = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-                freeScopeHeap();
+                m_utils.freeScopeHeap();
                 m_builder.CreateBr(statement.afterIf);
 
                 // Create else branch
@@ -1039,7 +990,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
             case LLVMInstruction::Type::EndIf: {
                 assert(!ifStatements.empty());
                 LLVMIfStatement &statement = ifStatements.back();
-                freeScopeHeap();
+                m_utils.freeScopeHeap();
 
                 // Jump to the branch after the if statement
                 if (!statement.afterIf)
@@ -1058,7 +1009,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 m_builder.SetInsertPoint(statement.afterIf);
 
                 ifStatements.pop_back();
-                popScopeLevel();
+                m_utils.popScopeLevel();
                 break;
             }
 
@@ -1068,7 +1019,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
                 // index = 0
                 llvm::Constant *zero = llvm::ConstantInt::get(m_builder.getInt64Ty(), 0, true);
-                loop.index = addAlloca(m_builder.getInt64Ty());
+                loop.index = m_utils.addAlloca(m_builder.getInt64Ty());
                 m_builder.CreateStore(zero, loop.index);
 
                 // Create branches
@@ -1080,7 +1031,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 assert(step.args.size() == 1);
                 const auto &reg = step.args[0];
                 assert(reg.first == Compiler::StaticType::Number);
-                llvm::Value *count = castValue(reg.second, reg.first);
+                llvm::Value *count = m_utils.castValue(reg.second, reg.first);
                 llvm::Value *isInf = m_builder.CreateFCmpOEQ(count, llvm::ConstantFP::getInfinity(m_builder.getDoubleTy(), false));
 
                 // Clamp count if <= 0 (we can skip the loop if count is not positive)
@@ -1113,7 +1064,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 m_builder.SetInsertPoint(body);
 
                 loops.push_back(loop);
-                pushScopeLevel();
+                m_utils.pushScopeLevel();
                 break;
             }
 
@@ -1137,12 +1088,12 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 assert(step.args.size() == 1);
                 const auto &reg = step.args[0];
                 assert(reg.first == Compiler::StaticType::Bool);
-                llvm::Value *condition = castValue(reg.second, reg.first);
+                llvm::Value *condition = m_utils.castValue(reg.second, reg.first);
                 m_builder.CreateCondBr(condition, body, loop.afterLoop);
 
                 // Switch to body branch
                 m_builder.SetInsertPoint(body);
-                pushScopeLevel();
+                m_utils.pushScopeLevel();
                 break;
             }
 
@@ -1158,12 +1109,12 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 assert(step.args.size() == 1);
                 const auto &reg = step.args[0];
                 assert(reg.first == Compiler::StaticType::Bool);
-                llvm::Value *condition = castValue(reg.second, reg.first);
+                llvm::Value *condition = m_utils.castValue(reg.second, reg.first);
                 m_builder.CreateCondBr(condition, loop.afterLoop, body);
 
                 // Switch to body branch
                 m_builder.SetInsertPoint(body);
-                pushScopeLevel();
+                m_utils.pushScopeLevel();
                 break;
             }
 
@@ -1189,19 +1140,19 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 }
 
                 // Jump to the condition branch
-                freeScopeHeap();
+                m_utils.freeScopeHeap();
                 m_builder.CreateBr(loop.conditionBranch);
 
                 // Switch to the branch after the loop
                 m_builder.SetInsertPoint(loop.afterLoop);
 
                 loops.pop_back();
-                popScopeLevel();
+                m_utils.popScopeLevel();
                 break;
             }
 
             case LLVMInstruction::Type::Stop: {
-                freeScopeHeap();
+                m_utils.freeScopeHeap();
                 m_builder.CreateBr(endBranch);
                 llvm::BasicBlock *nextBranch = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
                 m_builder.SetInsertPoint(nextBranch);
@@ -1211,8 +1162,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
             case LLVMInstruction::Type::CallProcedure: {
                 assert(step.procedurePrototype);
                 assert(step.args.size() == step.procedurePrototype->argumentTypes().size());
-                freeScopeHeap();
-                syncVariables(targetVariables);
+                m_utils.freeScopeHeap();
+                m_utils.syncVariables(targetVariables);
 
                 std::string name = getMainFunctionName(step.procedurePrototype);
                 llvm::FunctionType *type = getMainFunctionType(step.procedurePrototype);
@@ -1230,12 +1181,12 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 // Add procedure args
                 for (const auto &arg : step.args) {
                     if (arg.first == Compiler::StaticType::Unknown)
-                        args.push_back(createValue(arg.second));
+                        args.push_back(m_utils.createValue(arg.second));
                     else
-                        args.push_back(castValue(arg.second, arg.first));
+                        args.push_back(m_utils.castValue(arg.second, arg.first));
                 }
 
-                llvm::Value *handle = m_builder.CreateCall(m_functions.resolveFunction(name, type), args);
+                llvm::Value *handle = m_builder.CreateCall(m_utils.functions().resolveFunction(name, type), args);
 
                 if (!m_warp && !step.procedurePrototype->warp()) {
                     llvm::BasicBlock *suspendBranch = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
@@ -1250,7 +1201,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                     m_builder.SetInsertPoint(nextBranch);
                 }
 
-                reloadVariables(targetVariables);
+                m_utils.reloadVariables(targetVariables);
                 break;
             }
 
@@ -1263,12 +1214,11 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
         }
     }
 
-    assert(m_stringHeap.size() == 1);
-    freeScopeHeap();
+    m_utils.end();
     m_builder.CreateBr(endBranch);
 
     m_builder.SetInsertPoint(endBranch);
-    syncVariables(targetVariables);
+    m_utils.syncVariables(targetVariables);
 
     // End and verify the function
     llvm::PointerType *pointerType = llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0);
@@ -1285,7 +1235,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
             // Use last instruction return value (or last constant) and create a ValueData instance
             assert(!m_instructions.empty() || m_lastConstValue);
             LLVMRegister *ret = m_instructions.empty() ? m_lastConstValue : m_instructions.last()->functionReturnReg;
-            llvm::Value *copy = createNewValue(ret);
+            llvm::Value *copy = m_utils.createNewValue(ret);
             m_builder.CreateRet(m_builder.CreateLoad(m_valueDataType, copy));
             break;
         }
@@ -1295,9 +1245,9 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
             assert(!m_instructions.empty() || m_lastConstValue);
 
             if (m_instructions.empty())
-                m_builder.CreateRet(castValue(m_lastConstValue, Compiler::StaticType::Bool));
+                m_builder.CreateRet(m_utils.castValue(m_lastConstValue, Compiler::StaticType::Bool));
             else
-                m_builder.CreateRet(castValue(m_instructions.last()->functionReturnReg, Compiler::StaticType::Bool));
+                m_builder.CreateRet(m_utils.castValue(m_instructions.last()->functionReturnReg, Compiler::StaticType::Bool));
             break;
     }
 
@@ -1344,7 +1294,7 @@ CompilerValue *LLVMCodeBuilder::addFunctionCallWithCtx(const std::string &functi
 
 CompilerConstant *LLVMCodeBuilder::addConstValue(const Value &value)
 {
-    auto constReg = std::make_shared<LLVMConstantRegister>(TYPE_MAP[value.type()], value);
+    auto constReg = std::make_shared<LLVMConstantRegister>(m_utils.mapType(value.type()), value);
     auto reg = std::static_pointer_cast<LLVMRegister>(constReg);
     m_lastConstValue = reg.get();
     return static_cast<CompilerConstant *>(static_cast<LLVMConstantRegister *>(addReg(reg, nullptr)));
@@ -1374,16 +1324,13 @@ CompilerValue *LLVMCodeBuilder::addVariableValue(Variable *variable)
 {
     auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::ReadVariable, m_loopCondition);
     ins->workVariable = variable;
-
-    if (m_variablePtrs.find(variable) == m_variablePtrs.cend())
-        m_variablePtrs[variable] = LLVMVariablePtr();
+    m_utils.createVariablePtr(variable);
 
     auto ret = std::make_shared<LLVMRegister>(Compiler::StaticType::Unknown);
     ret->isRawValue = false;
     ins->functionReturnReg = ret.get();
 
     m_instructions.addInstruction(ins);
-    m_variableInstructions.push_back(ins.get());
     return addReg(ret, ins);
 }
 
@@ -1391,9 +1338,7 @@ CompilerValue *LLVMCodeBuilder::addListContents(List *list)
 {
     LLVMInstruction ins(LLVMInstruction::Type::GetListContents, m_loopCondition);
     ins.workList = list;
-
-    if (m_listPtrs.find(list) == m_listPtrs.cend())
-        m_listPtrs[list] = LLVMListPtr();
+    m_utils.createListPtr(list);
 
     return createOp(ins, Compiler::StaticType::String);
 }
@@ -1402,9 +1347,7 @@ CompilerValue *LLVMCodeBuilder::addListItem(List *list, CompilerValue *index)
 {
     auto ins = std::make_shared<LLVMInstruction>(LLVMInstruction::Type::GetListItem, m_loopCondition);
     ins->workList = list;
-
-    if (m_listPtrs.find(list) == m_listPtrs.cend())
-        m_listPtrs[list] = LLVMListPtr();
+    m_utils.createListPtr(list);
 
     ins->args.push_back({ Compiler::StaticType::Number, dynamic_cast<LLVMRegister *>(index) });
 
@@ -1413,7 +1356,6 @@ CompilerValue *LLVMCodeBuilder::addListItem(List *list, CompilerValue *index)
     ins->functionReturnReg = ret.get();
 
     m_instructions.addInstruction(ins);
-    m_listInstructions.push_back(ins.get());
     return addReg(ret, ins);
 }
 
@@ -1421,12 +1363,9 @@ CompilerValue *LLVMCodeBuilder::addListItemIndex(List *list, CompilerValue *item
 {
     LLVMInstruction ins(LLVMInstruction::Type::GetListItemIndex, m_loopCondition);
     ins.workList = list;
-
-    if (m_listPtrs.find(list) == m_listPtrs.cend())
-        m_listPtrs[list] = LLVMListPtr();
+    m_utils.createListPtr(list);
 
     auto ret = createOp(ins, Compiler::StaticType::Number, Compiler::StaticType::Unknown, { item });
-    m_listInstructions.push_back(m_instructions.last());
     return ret;
 }
 
@@ -1434,12 +1373,9 @@ CompilerValue *LLVMCodeBuilder::addListContains(List *list, CompilerValue *item)
 {
     LLVMInstruction ins(LLVMInstruction::Type::ListContainsItem, m_loopCondition);
     ins.workList = list;
-
-    if (m_listPtrs.find(list) == m_listPtrs.cend())
-        m_listPtrs[list] = LLVMListPtr();
+    m_utils.createListPtr(list);
 
     auto ret = createOp(ins, Compiler::StaticType::Bool, Compiler::StaticType::Unknown, { item });
-    m_listInstructions.push_back(m_instructions.last());
     return ret;
 }
 
@@ -1447,9 +1383,7 @@ CompilerValue *LLVMCodeBuilder::addListSize(List *list)
 {
     LLVMInstruction ins(LLVMInstruction::Type::GetListSize, m_loopCondition);
     ins.workList = list;
-
-    if (m_listPtrs.find(list) == m_listPtrs.cend())
-        m_listPtrs[list] = LLVMListPtr();
+    m_utils.createListPtr(list);
 
     return createOp(ins, Compiler::StaticType::Number);
 }
@@ -1657,11 +1591,7 @@ void LLVMCodeBuilder::createVariableWrite(Variable *variable, CompilerValue *val
     LLVMInstruction ins(LLVMInstruction::Type::WriteVariable, m_loopCondition);
     ins.workVariable = variable;
     createOp(ins, Compiler::StaticType::Void, Compiler::StaticType::Unknown, { value });
-
-    if (m_variablePtrs.find(variable) == m_variablePtrs.cend())
-        m_variablePtrs[variable] = LLVMVariablePtr();
-
-    m_variableInstructions.push_back(m_instructions.last());
+    m_utils.createVariablePtr(variable);
 }
 
 void LLVMCodeBuilder::createListClear(List *list)
@@ -1669,9 +1599,7 @@ void LLVMCodeBuilder::createListClear(List *list)
     LLVMInstruction ins(LLVMInstruction::Type::ClearList, m_loopCondition);
     ins.workList = list;
     createOp(ins, Compiler::StaticType::Void);
-
-    if (m_listPtrs.find(list) == m_listPtrs.cend())
-        m_listPtrs[list] = LLVMListPtr();
+    m_utils.createListPtr(list);
 }
 
 void LLVMCodeBuilder::createListRemove(List *list, CompilerValue *index)
@@ -1679,9 +1607,7 @@ void LLVMCodeBuilder::createListRemove(List *list, CompilerValue *index)
     LLVMInstruction ins(LLVMInstruction::Type::RemoveListItem, m_loopCondition);
     ins.workList = list;
     createOp(ins, Compiler::StaticType::Void, Compiler::StaticType::Number, { index });
-
-    if (m_listPtrs.find(list) == m_listPtrs.cend())
-        m_listPtrs[list] = LLVMListPtr();
+    m_utils.createListPtr(list);
 }
 
 void LLVMCodeBuilder::createListAppend(List *list, CompilerValue *item)
@@ -1689,11 +1615,7 @@ void LLVMCodeBuilder::createListAppend(List *list, CompilerValue *item)
     LLVMInstruction ins(LLVMInstruction::Type::AppendToList, m_loopCondition);
     ins.workList = list;
     createOp(ins, Compiler::StaticType::Void, Compiler::StaticType::Unknown, { item });
-
-    if (m_listPtrs.find(list) == m_listPtrs.cend())
-        m_listPtrs[list] = LLVMListPtr();
-
-    m_listInstructions.push_back(m_instructions.last());
+    m_utils.createListPtr(list);
 }
 
 void LLVMCodeBuilder::createListInsert(List *list, CompilerValue *index, CompilerValue *item)
@@ -1701,11 +1623,7 @@ void LLVMCodeBuilder::createListInsert(List *list, CompilerValue *index, Compile
     LLVMInstruction ins(LLVMInstruction::Type::InsertToList, m_loopCondition);
     ins.workList = list;
     createOp(ins, Compiler::StaticType::Void, { Compiler::StaticType::Number, Compiler::StaticType::Unknown }, { index, item });
-
-    if (m_listPtrs.find(list) == m_listPtrs.cend())
-        m_listPtrs[list] = LLVMListPtr();
-
-    m_listInstructions.push_back(m_instructions.last());
+    m_utils.createListPtr(list);
 }
 
 void LLVMCodeBuilder::createListReplace(List *list, CompilerValue *index, CompilerValue *item)
@@ -1713,11 +1631,7 @@ void LLVMCodeBuilder::createListReplace(List *list, CompilerValue *index, Compil
     LLVMInstruction ins(LLVMInstruction::Type::ListReplace, m_loopCondition);
     ins.workList = list;
     createOp(ins, Compiler::StaticType::Void, { Compiler::StaticType::Number, Compiler::StaticType::Unknown }, { index, item });
-
-    if (m_listPtrs.find(list) == m_listPtrs.cend())
-        m_listPtrs[list] = LLVMListPtr();
-
-    m_listInstructions.push_back(m_instructions.last());
+    m_utils.createListPtr(list);
 }
 
 void LLVMCodeBuilder::beginIfStatement(CompilerValue *cond)
@@ -1817,82 +1731,10 @@ void LLVMCodeBuilder::createProcedureCall(BlockPrototype *prototype, const Compi
 
 void LLVMCodeBuilder::initTypes()
 {
-    llvm::PointerType *pointerType = llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0);
     m_valueDataType = m_ctx->valueDataType();
     m_stringPtrType = m_ctx->stringPtrType();
 }
 
-void LLVMCodeBuilder::createVariableMap()
-{
-    if (!m_target)
-        return;
-
-    // Map variable pointers to variable data array indices
-    const auto &variables = m_target->variables();
-    ValueData **variableData = m_target->variableData();
-    const size_t len = variables.size();
-    m_targetVariableMap.clear();
-    m_targetVariableMap.reserve(len);
-
-    size_t i, j;
-
-    for (i = 0; i < len; i++) {
-        Variable *var = variables[i].get();
-
-        // Find the data for this variable
-        for (j = 0; j < len; j++) {
-            if (variableData[j] == &var->valuePtr()->data())
-                break;
-        }
-
-        if (j < len)
-            m_targetVariableMap[var] = j;
-        else
-            assert(false);
-    }
-}
-
-void LLVMCodeBuilder::createListMap()
-{
-    if (!m_target)
-        return;
-
-    // Map list pointers to list array indices
-    const auto &lists = m_target->lists();
-    List **listData = m_target->listData();
-    const size_t len = lists.size();
-    m_targetListMap.clear();
-    m_targetListMap.reserve(len);
-
-    size_t i, j;
-
-    for (i = 0; i < len; i++) {
-        List *list = lists[i].get();
-
-        // Find this list
-        for (j = 0; j < len; j++) {
-            if (listData[j] == list)
-                break;
-        }
-
-        if (j < len)
-            m_targetListMap[list] = j;
-        else
-            assert(false);
-    }
-}
-
-void LLVMCodeBuilder::pushScopeLevel()
-{
-    m_stringHeap.push_back({});
-}
-
-void LLVMCodeBuilder::popScopeLevel()
-{
-    freeScopeHeap();
-    m_stringHeap.pop_back();
-}
-
 std::string LLVMCodeBuilder::getMainFunctionName(BlockPrototype *procedurePrototype)
 {
     std::string name;
@@ -1978,355 +1820,11 @@ LLVMRegister *LLVMCodeBuilder::addReg(std::shared_ptr<LLVMRegister> reg, std::sh
     return reg.get();
 }
 
-llvm::Value *LLVMCodeBuilder::addAlloca(llvm::Type *type)
-{
-    // Add an alloca to the entry block because allocas must be there (to avoid stack overflow)
-    llvm::BasicBlock *block = m_builder.GetInsertBlock();
-    m_builder.SetInsertPointPastAllocas(m_function);
-    llvm::Value *ret = m_builder.CreateAlloca(type);
-    m_builder.SetInsertPoint(block);
-    return ret;
-}
-
-void LLVMCodeBuilder::freeStringLater(llvm::Value *value)
-{
-    assert(!m_stringHeap.empty());
-
-    if (m_stringHeap.empty())
-        return;
-
-    m_stringHeap.back().push_back(value);
-}
-
-void LLVMCodeBuilder::freeScopeHeap()
-{
-    if (m_stringHeap.empty())
-        return;
-
-    // Free strings in current scope
-    auto &heap = m_stringHeap.back();
-
-    for (llvm::Value *ptr : heap)
-        m_builder.CreateCall(m_functions.resolve_string_pool_free(), { ptr });
-
-    heap.clear();
-}
-
-llvm::Value *LLVMCodeBuilder::castValue(LLVMRegister *reg, Compiler::StaticType targetType)
-{
-    if (reg->isConst()) {
-        if (targetType == Compiler::StaticType::Unknown)
-            return createValue(reg);
-        else
-            return castConstValue(reg->constValue(), targetType);
-    }
-
-    if (reg->isRawValue)
-        return castRawValue(reg, targetType);
-
-    assert(reg->type() != Compiler::StaticType::Void && targetType != Compiler::StaticType::Void);
-
-    switch (targetType) {
-        case Compiler::StaticType::Number:
-            switch (reg->type()) {
-                case Compiler::StaticType::Number: {
-                    // Read number directly
-                    llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 0);
-                    return m_builder.CreateLoad(m_builder.getDoubleTy(), ptr);
-                }
-
-                case Compiler::StaticType::Bool: {
-                    // Read boolean and cast to double
-                    llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 0);
-                    llvm::Value *boolValue = m_builder.CreateLoad(m_builder.getInt1Ty(), ptr);
-                    return m_builder.CreateSIToFP(boolValue, m_builder.getDoubleTy());
-                }
-
-                case Compiler::StaticType::String:
-                case Compiler::StaticType::Unknown: {
-                    // Convert to double
-                    return m_builder.CreateCall(m_functions.resolve_value_toDouble(), reg->value);
-                }
-
-                default:
-                    assert(false);
-                    return nullptr;
-            }
-
-        case Compiler::StaticType::Bool:
-            switch (reg->type()) {
-                case Compiler::StaticType::Number: {
-                    // True if != 0
-                    llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 0);
-                    llvm::Value *numberValue = m_builder.CreateLoad(m_builder.getDoubleTy(), ptr);
-                    return m_builder.CreateFCmpONE(numberValue, llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0)));
-                }
-
-                case Compiler::StaticType::Bool: {
-                    // Read boolean directly
-                    llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 0);
-                    return m_builder.CreateLoad(m_builder.getInt1Ty(), ptr);
-                }
-
-                case Compiler::StaticType::String:
-                case Compiler::StaticType::Unknown:
-                    // Convert to bool
-                    return m_builder.CreateCall(m_functions.resolve_value_toBool(), reg->value);
-
-                default:
-                    assert(false);
-                    return nullptr;
-            }
-
-        case Compiler::StaticType::String:
-            switch (reg->type()) {
-                case Compiler::StaticType::Number:
-                case Compiler::StaticType::Bool:
-                case Compiler::StaticType::Unknown: {
-                    // Cast to string
-                    // TODO: Use value_stringToDouble() and value_stringToBool()
-                    llvm::Value *ptr = m_builder.CreateCall(m_functions.resolve_value_toStringPtr(), reg->value);
-                    freeStringLater(ptr);
-                    return ptr;
-                }
-
-                case Compiler::StaticType::String: {
-                    // Read string pointer directly
-                    llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 0);
-                    return m_builder.CreateLoad(m_stringPtrType->getPointerTo(), ptr);
-                }
-
-                default:
-                    assert(false);
-                    return nullptr;
-            }
-
-        case Compiler::StaticType::Unknown:
-            return createValue(reg);
-
-        default:
-            assert(false);
-            return nullptr;
-    }
-}
-
-llvm::Value *LLVMCodeBuilder::castRawValue(LLVMRegister *reg, Compiler::StaticType targetType)
-{
-    if (reg->type() == targetType)
-        return reg->value;
-
-    switch (targetType) {
-        case Compiler::StaticType::Number:
-            switch (reg->type()) {
-                case Compiler::StaticType::Bool:
-                    // Cast bool to double
-                    return m_builder.CreateUIToFP(reg->value, m_builder.getDoubleTy());
-
-                case Compiler::StaticType::String: {
-                    // Convert string to double
-                    return m_builder.CreateCall(m_functions.resolve_value_stringToDouble(), reg->value);
-                }
-
-                default:
-                    assert(false);
-                    return nullptr;
-            }
-
-        case Compiler::StaticType::Bool:
-            switch (reg->type()) {
-                case Compiler::StaticType::Number:
-                    // Cast double to bool (true if != 0)
-                    return m_builder.CreateFCmpONE(reg->value, llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0)));
-
-                case Compiler::StaticType::String:
-                    // Convert string to bool
-                    return m_builder.CreateCall(m_functions.resolve_value_stringToBool(), reg->value);
-
-                default:
-                    assert(false);
-                    return nullptr;
-            }
-
-        case Compiler::StaticType::String:
-            switch (reg->type()) {
-                case Compiler::StaticType::Number: {
-                    // Convert double to string
-                    llvm::Value *ptr = m_builder.CreateCall(m_functions.resolve_value_doubleToStringPtr(), reg->value);
-                    freeStringLater(ptr);
-                    return ptr;
-                }
-
-                case Compiler::StaticType::Bool: {
-                    // Convert bool to string
-                    llvm::Value *ptr = m_builder.CreateCall(m_functions.resolve_value_boolToStringPtr(), reg->value);
-                    // NOTE: Dot not deallocate later
-                    return ptr;
-                }
-
-                default:
-                    assert(false);
-                    return nullptr;
-            }
-
-        case Compiler::StaticType::Unknown:
-            return createValue(reg);
-
-        default:
-            assert(false);
-            return nullptr;
-    }
-}
-
-llvm::Constant *LLVMCodeBuilder::castConstValue(const Value &value, Compiler::StaticType targetType)
-{
-    switch (targetType) {
-        case Compiler::StaticType::Number: {
-            const double nan = std::numeric_limits<double>::quiet_NaN();
-            return llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(value.isNaN() ? nan : value.toDouble()));
-        }
-
-        case Compiler::StaticType::Bool:
-            return m_builder.getInt1(value.toBool());
-
-        case Compiler::StaticType::String: {
-            std::u16string str = value.toUtf16();
-
-            // Create a constant array for the string
-            std::vector<llvm::Constant *> elements;
-            for (char16_t ch : str)
-                elements.push_back(m_builder.getInt16(ch));
-
-            elements.push_back(m_builder.getInt16(0)); // null terminator
-
-            llvm::ArrayType *arrayType = llvm::ArrayType::get(m_builder.getInt16Ty(), elements.size());
-            llvm::Constant *constArray = llvm::ConstantArray::get(arrayType, elements);
-
-            llvm::Constant *globalStr = new llvm::GlobalVariable(*m_module, arrayType, true, llvm::GlobalValue::PrivateLinkage, constArray, "string");
-            llvm::Constant *stringStruct = llvm::ConstantStruct::get(m_stringPtrType, { globalStr, m_builder.getInt64(str.size()), m_builder.getInt64(str.size() + 1) });
-            return new llvm::GlobalVariable(*m_module, m_stringPtrType, true, llvm::GlobalValue::PrivateLinkage, stringStruct, "stringPtr");
-        }
-
-        case Compiler::StaticType::Pointer: {
-            llvm::Constant *addr = m_builder.getInt64((uintptr_t)value.toPointer());
-            return llvm::ConstantExpr::getIntToPtr(addr, m_builder.getVoidTy()->getPointerTo());
-        }
-
-        default:
-            assert(false);
-            return nullptr;
-    }
-}
-
-Compiler::StaticType LLVMCodeBuilder::optimizeRegisterType(LLVMRegister *reg) const
-{
-    Compiler::StaticType ret = reg->type();
-
-    // Optimize string constants that represent numbers
-    if (reg->isConst() && reg->type() == Compiler::StaticType::String && reg->constValue().isValidNumber())
-        ret = Compiler::StaticType::Number;
-
-    return ret;
-}
-
-llvm::Type *LLVMCodeBuilder::getType(Compiler::StaticType type)
-{
-    switch (type) {
-        case Compiler::StaticType::Void:
-            return m_builder.getVoidTy();
-
-        case Compiler::StaticType::Number:
-            return m_builder.getDoubleTy();
-
-        case Compiler::StaticType::Bool:
-            return m_builder.getInt1Ty();
-
-        case Compiler::StaticType::String:
-            return m_stringPtrType->getPointerTo();
-
-        case Compiler::StaticType::Pointer:
-            return m_builder.getVoidTy()->getPointerTo();
-
-        case Compiler::StaticType::Unknown:
-            return m_valueDataType->getPointerTo();
-
-        default:
-            assert(false);
-            return nullptr;
-    }
-}
-
 Compiler::StaticType LLVMCodeBuilder::getProcedureArgType(BlockPrototype::ArgType type)
 {
     return type == BlockPrototype::ArgType::Bool ? Compiler::StaticType::Bool : Compiler::StaticType::Unknown;
 }
 
-llvm::Value *LLVMCodeBuilder::isNaN(llvm::Value *num)
-{
-    return m_builder.CreateFCmpUNO(num, num);
-}
-
-llvm::Value *LLVMCodeBuilder::removeNaN(llvm::Value *num)
-{
-    // Replace NaN with zero
-    return m_builder.CreateSelect(isNaN(num), llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0)), num);
-}
-
-llvm::Value *LLVMCodeBuilder::getVariablePtr(llvm::Value *targetVariables, Variable *variable)
-{
-    if (!m_target->isStage() && variable->target() == m_target) {
-        // If this is a local sprite variable, use the variable array at runtime (for clones)
-        assert(m_targetVariableMap.find(variable) != m_targetVariableMap.cend());
-        const size_t index = m_targetVariableMap[variable];
-        llvm::Value *ptr = m_builder.CreateGEP(m_valueDataType->getPointerTo(), targetVariables, m_builder.getInt64(index));
-        return m_builder.CreateLoad(m_valueDataType->getPointerTo(), ptr);
-    }
-
-    // Otherwise create a raw pointer at compile time
-    llvm::Value *addr = m_builder.getInt64((uintptr_t)&variable->value().data());
-    return m_builder.CreateIntToPtr(addr, m_valueDataType->getPointerTo());
-}
-
-llvm::Value *LLVMCodeBuilder::getListPtr(llvm::Value *targetLists, List *list)
-{
-    if (!m_target->isStage() && list->target() == m_target) {
-        // If this is a local sprite list, use the list array at runtime (for clones)
-        assert(m_targetListMap.find(list) != m_targetListMap.cend());
-        const size_t index = m_targetListMap[list];
-        auto pointerType = llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0);
-        llvm::Value *ptr = m_builder.CreateGEP(pointerType, targetLists, m_builder.getInt64(index));
-        return m_builder.CreateLoad(pointerType, ptr);
-    }
-
-    // Otherwise create a raw pointer at compile time
-    llvm::Value *addr = m_builder.getInt64((uintptr_t)list);
-    return m_builder.CreateIntToPtr(addr, m_valueDataType->getPointerTo());
-}
-
-llvm::Value *LLVMCodeBuilder::getListDataPtr(const LLVMListPtr &listPtr)
-{
-    return m_builder.CreateLoad(m_valueDataType->getPointerTo(), m_builder.CreateLoad(m_valueDataType->getPointerTo()->getPointerTo(), listPtr.dataPtr));
-}
-
-void LLVMCodeBuilder::syncVariables(llvm::Value *targetVariables)
-{
-    // Copy stack variables to the actual variables
-    for (auto &[var, varPtr] : m_variablePtrs) {
-        if (varPtr.onStack && varPtr.changed)
-            createValueCopy(varPtr.stackPtr, getVariablePtr(targetVariables, var));
-
-        varPtr.changed = false;
-    }
-}
-
-void LLVMCodeBuilder::reloadVariables(llvm::Value *targetVariables)
-{
-    // Reset variables to use heap
-    for (auto &[var, varPtr] : m_variablePtrs) {
-        varPtr.onStack = false;
-        varPtr.changed = false;
-    }
-}
-
 LLVMRegister *LLVMCodeBuilder::createOp(LLVMInstruction::Type type, Compiler::StaticType retType, Compiler::StaticType argType, const Compiler::Args &args)
 {
     return createOp({ type, m_loopCondition }, retType, argType, args);
@@ -2366,457 +1864,6 @@ LLVMRegister *LLVMCodeBuilder::createOp(const LLVMInstruction &ins, Compiler::St
     return nullptr;
 }
 
-void LLVMCodeBuilder::createValueStore(LLVMRegister *reg, llvm::Value *targetPtr, Compiler::StaticType sourceType, Compiler::StaticType targetType)
-{
-    llvm::Value *converted = nullptr;
-
-    if (sourceType != Compiler::StaticType::Unknown)
-        converted = castValue(reg, sourceType);
-
-    auto it = std::find_if(TYPE_MAP.begin(), TYPE_MAP.end(), [sourceType](const std::pair<ValueType, Compiler::StaticType> &pair) { return pair.second == sourceType; });
-    const ValueType mappedType = it == TYPE_MAP.cend() ? ValueType::Number : it->first; // unknown type can be ignored
-
-    switch (sourceType) {
-        case Compiler::StaticType::Number:
-            switch (targetType) {
-                case Compiler::StaticType::Number: {
-                    // Write number to number directly
-                    llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, targetPtr, 0);
-                    m_builder.CreateStore(converted, ptr);
-                    break;
-                }
-
-                case Compiler::StaticType::Bool: {
-                    // Write number to bool value directly and change type
-                    llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, targetPtr, 0);
-                    llvm::Value *typePtr = m_builder.CreateStructGEP(m_valueDataType, targetPtr, 1);
-                    m_builder.CreateStore(converted, ptr);
-                    m_builder.CreateStore(m_builder.getInt32(static_cast<uint32_t>(mappedType)), typePtr);
-                    break;
-                }
-
-                default:
-                    m_builder.CreateCall(m_functions.resolve_value_assign_double(), { targetPtr, converted });
-                    break;
-            }
-
-            break;
-
-        case Compiler::StaticType::Bool:
-            switch (targetType) {
-                case Compiler::StaticType::Number: {
-                    // Write bool to number value directly and change type
-                    llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, targetPtr, 0);
-                    m_builder.CreateStore(converted, ptr);
-                    llvm::Value *typePtr = m_builder.CreateStructGEP(m_valueDataType, targetPtr, 1);
-                    m_builder.CreateStore(converted, ptr);
-                    m_builder.CreateStore(m_builder.getInt32(static_cast<uint32_t>(mappedType)), typePtr);
-                    break;
-                }
-
-                case Compiler::StaticType::Bool: {
-                    // Write bool to bool directly
-                    llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, targetPtr, 0);
-                    m_builder.CreateStore(converted, ptr);
-                    break;
-                }
-
-                default:
-                    m_builder.CreateCall(m_functions.resolve_value_assign_bool(), { targetPtr, converted });
-                    break;
-            }
-
-            break;
-
-        case Compiler::StaticType::String:
-            m_builder.CreateCall(m_functions.resolve_value_assign_stringPtr(), { targetPtr, converted });
-            break;
-
-        case Compiler::StaticType::Unknown:
-            m_builder.CreateCall(m_functions.resolve_value_assign_copy(), { targetPtr, reg->value });
-            break;
-
-        default:
-            assert(false);
-            break;
-    }
-}
-
-void LLVMCodeBuilder::createReusedValueStore(LLVMRegister *reg, llvm::Value *targetPtr, Compiler::StaticType sourceType, Compiler::StaticType targetType)
-{
-    // Same as createValueStore(), but ensures that type is updated
-    createValueStore(reg, targetPtr, sourceType, targetType);
-
-    auto it = std::find_if(TYPE_MAP.begin(), TYPE_MAP.end(), [sourceType](const std::pair<ValueType, Compiler::StaticType> &pair) { return pair.second == sourceType; });
-    const ValueType mappedType = it == TYPE_MAP.cend() ? ValueType::Number : it->first; // unknown type can be ignored
-
-    if ((sourceType == Compiler::StaticType::Number || sourceType == Compiler::StaticType::Bool) && sourceType == targetType) {
-        // Update type when writing number to number and bool to bool
-        llvm::Value *typePtr = m_builder.CreateStructGEP(m_valueDataType, targetPtr, 1);
-        m_builder.CreateStore(m_builder.getInt32(static_cast<uint32_t>(mappedType)), typePtr);
-    }
-}
-
-void LLVMCodeBuilder::createValueCopy(llvm::Value *source, llvm::Value *target)
-{
-    // NOTE: This doesn't copy strings, but only the pointers
-    copyStructField(source, target, 0, m_valueDataType, m_builder.getInt64Ty()); // value
-    copyStructField(source, target, 1, m_valueDataType, m_builder.getInt32Ty()); // type
-    /* 2: padding */
-}
-
-void LLVMCodeBuilder::copyStructField(llvm::Value *source, llvm::Value *target, int index, llvm::StructType *structType, llvm::Type *fieldType)
-{
-    llvm::Value *sourceField = m_builder.CreateStructGEP(structType, source, index);
-    llvm::Value *targetField = m_builder.CreateStructGEP(structType, target, index);
-    m_builder.CreateStore(m_builder.CreateLoad(fieldType, sourceField), targetField);
-}
-
-llvm::Value *LLVMCodeBuilder::getListItem(const LLVMListPtr &listPtr, llvm::Value *index)
-{
-    return m_builder.CreateGEP(m_valueDataType, getListDataPtr(listPtr), index);
-}
-
-llvm::Value *LLVMCodeBuilder::getListItemIndex(const LLVMListPtr &listPtr, Compiler::StaticType listType, LLVMRegister *item)
-{
-    llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.sizePtr);
-    llvm::BasicBlock *condBlock = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-    llvm::BasicBlock *bodyBlock = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-    llvm::BasicBlock *cmpIfBlock = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-    llvm::BasicBlock *cmpElseBlock = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-    llvm::BasicBlock *notFoundBlock = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-    llvm::BasicBlock *nextBlock = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-
-    // index = 0
-    llvm::Value *index = addAlloca(m_builder.getInt64Ty());
-    m_builder.CreateStore(m_builder.getInt64(0), index);
-    m_builder.CreateBr(condBlock);
-
-    // while (index < size)
-    m_builder.SetInsertPoint(condBlock);
-    llvm::Value *cond = m_builder.CreateICmpULT(m_builder.CreateLoad(m_builder.getInt64Ty(), index), size);
-    m_builder.CreateCondBr(cond, bodyBlock, notFoundBlock);
-
-    // if (list[index] == item)
-    m_builder.SetInsertPoint(bodyBlock);
-    LLVMRegister currentItem(listType);
-    currentItem.isRawValue = false;
-    currentItem.value = getListItem(listPtr, m_builder.CreateLoad(m_builder.getInt64Ty(), index));
-    llvm::Value *cmp = createComparison(&currentItem, item, Comparison::EQ);
-    m_builder.CreateCondBr(cmp, cmpIfBlock, cmpElseBlock);
-
-    // goto nextBlock
-    m_builder.SetInsertPoint(cmpIfBlock);
-    m_builder.CreateBr(nextBlock);
-
-    // else index++
-    m_builder.SetInsertPoint(cmpElseBlock);
-    m_builder.CreateStore(m_builder.CreateAdd(m_builder.CreateLoad(m_builder.getInt64Ty(), index), m_builder.getInt64(1)), index);
-    m_builder.CreateBr(condBlock);
-
-    // notFoundBlock:
-    // index = -1
-    // goto nextBlock
-    m_builder.SetInsertPoint(notFoundBlock);
-    m_builder.CreateStore(llvm::ConstantInt::get(llvm::Type::getInt64Ty(m_llvmCtx), -1, true), index);
-    m_builder.CreateBr(nextBlock);
-
-    // nextBlock:
-    m_builder.SetInsertPoint(nextBlock);
-
-    return m_builder.CreateLoad(m_builder.getInt64Ty(), index);
-}
-
-llvm::Value *LLVMCodeBuilder::createValue(LLVMRegister *reg)
-{
-    if (reg->isConst()) {
-        // Create a constant ValueData instance and store it
-        llvm::Constant *value = castConstValue(reg->constValue(), TYPE_MAP[reg->constValue().type()]);
-        llvm::Value *ret = addAlloca(m_valueDataType);
-
-        switch (reg->constValue().type()) {
-            case ValueType::Number:
-                value = llvm::ConstantExpr::getBitCast(value, m_valueDataType->getElementType(0));
-                break;
-
-            case ValueType::Bool:
-                // Assuming union type is int64
-                value = m_builder.getInt64(reg->constValue().toBool());
-                break;
-
-            case ValueType::String:
-            case ValueType::Pointer:
-                value = llvm::ConstantExpr::getPtrToInt(value, m_valueDataType->getElementType(0));
-                break;
-
-            default:
-                assert(false);
-                break;
-        }
-
-        llvm::Constant *type = m_builder.getInt32(static_cast<uint32_t>(reg->constValue().type()));
-        llvm::Constant *padding = m_builder.getInt32(0);
-        llvm::Constant *constValue = llvm::ConstantStruct::get(m_valueDataType, { value, type, padding });
-        m_builder.CreateStore(constValue, ret);
-
-        return ret;
-    } else if (reg->isRawValue) {
-        llvm::Value *value = castRawValue(reg, reg->type());
-        llvm::Value *ret = addAlloca(m_valueDataType);
-
-        // Store value
-        llvm::Value *valueField = m_builder.CreateStructGEP(m_valueDataType, ret, 0);
-        m_builder.CreateStore(value, valueField);
-
-        auto it = std::find_if(TYPE_MAP.begin(), TYPE_MAP.end(), [&reg](const std::pair<ValueType, Compiler::StaticType> &pair) { return pair.second == reg->type(); });
-
-        if (it == TYPE_MAP.end()) {
-            assert(false);
-            return nullptr;
-        }
-
-        // Store type
-        llvm::Value *typeField = m_builder.CreateStructGEP(m_valueDataType, ret, 1);
-        ValueType type = it->first;
-        m_builder.CreateStore(m_builder.getInt32(static_cast<uint32_t>(type)), typeField);
-
-        return ret;
-    } else
-        return reg->value;
-}
-
-llvm::Value *LLVMCodeBuilder::createNewValue(LLVMRegister *reg)
-{
-    // Same as createValue(), but creates a copy of the contents
-    // NOTE: It is the caller's responsibility to free the value.
-    llvm::Value *value = createValue(reg);
-    llvm::Value *ret = addAlloca(m_valueDataType);
-    m_builder.CreateCall(m_functions.resolve_value_init(), { ret });
-    m_builder.CreateCall(m_functions.resolve_value_assign_copy(), { ret, value });
-    return ret;
-}
-
-llvm::Value *LLVMCodeBuilder::createComparison(LLVMRegister *arg1, LLVMRegister *arg2, Comparison type)
-{
-    auto type1 = arg1->type();
-    auto type2 = arg2->type();
-
-    if (arg1->isConst() && arg2->isConst()) {
-        // If both operands are constant, perform the comparison at compile time
-        bool result = false;
-
-        switch (type) {
-            case Comparison::EQ:
-                result = arg1->constValue() == arg2->constValue();
-                break;
-
-            case Comparison::GT:
-                result = arg1->constValue() > arg2->constValue();
-                break;
-
-            case Comparison::LT:
-                result = arg1->constValue() < arg2->constValue();
-                break;
-
-            default:
-                assert(false);
-                return nullptr;
-        }
-
-        return m_builder.getInt1(result);
-    } else {
-        // Optimize comparison of constant with number/bool
-        if (arg1->isConst() && arg1->constValue().isValidNumber() && (type2 == Compiler::StaticType::Number || type2 == Compiler::StaticType::Bool))
-            type1 = Compiler::StaticType::Number;
-
-        if (arg2->isConst() && arg2->constValue().isValidNumber() && (type1 == Compiler::StaticType::Number || type1 == Compiler::StaticType::Bool))
-            type2 = Compiler::StaticType::Number;
-
-        // Optimize number and bool comparison
-        int optNumberBool = 0;
-
-        if (type1 == Compiler::StaticType::Number && type2 == Compiler::StaticType::Bool) {
-            type2 = Compiler::StaticType::Number;
-            optNumberBool = 2; // operand 2 was bool
-        }
-
-        if (type1 == Compiler::StaticType::Bool && type2 == Compiler::StaticType::Number) {
-            type1 = Compiler::StaticType::Number;
-            optNumberBool = 1; // operand 1 was bool
-        }
-
-        // Optimize number and string constant comparison
-        // TODO: GT and LT comparison can be optimized here (e. g. by checking the string constant characters and comparing with numbers and .+-e)
-        if (type == Comparison::EQ) {
-            if ((type1 == Compiler::StaticType::Number && type2 == Compiler::StaticType::String && arg2->isConst() && !arg2->constValue().isValidNumber()) ||
-                (type1 == Compiler::StaticType::String && type2 == Compiler::StaticType::Number && arg1->isConst() && !arg1->constValue().isValidNumber()))
-                return m_builder.getInt1(false);
-        }
-
-        if (type1 != type2 || type1 == Compiler::StaticType::Unknown || type2 == Compiler::StaticType::Unknown) {
-            // If the types are different or at least one of them
-            // is unknown, we must use value functions
-            llvm::Value *value1 = createValue(arg1);
-            llvm::Value *value2 = createValue(arg2);
-
-            switch (type) {
-                case Comparison::EQ:
-                    return m_builder.CreateCall(m_functions.resolve_value_equals(), { value1, value2 });
-
-                case Comparison::GT:
-                    return m_builder.CreateCall(m_functions.resolve_value_greater(), { value1, value2 });
-
-                case Comparison::LT:
-                    return m_builder.CreateCall(m_functions.resolve_value_lower(), { value1, value2 });
-
-                default:
-                    assert(false);
-                    return nullptr;
-            }
-        } else {
-            // Compare raw values
-            llvm::Value *value1 = castValue(arg1, type1);
-            llvm::Value *value2 = castValue(arg2, type2);
-            assert(type1 == type2);
-
-            switch (type1) {
-                case Compiler::StaticType::Number: {
-                    // Compare two numbers
-                    switch (type) {
-                        case Comparison::EQ: {
-                            llvm::Value *nan = m_builder.CreateAnd(isNaN(value1), isNaN(value2)); // NaN == NaN
-                            llvm::Value *cmp = m_builder.CreateFCmpOEQ(value1, value2);
-                            return m_builder.CreateSelect(nan, m_builder.getInt1(true), cmp);
-                        }
-
-                        case Comparison::GT: {
-                            llvm::Value *bothNan = m_builder.CreateAnd(isNaN(value1), isNaN(value2)); // NaN == NaN
-                            llvm::Value *cmp = m_builder.CreateFCmpOGT(value1, value2);
-                            llvm::Value *nan;
-                            llvm::Value *nanCmp;
-
-                            if (optNumberBool == 1) {
-                                nan = isNaN(value2);
-                                nanCmp = castValue(arg1, Compiler::StaticType::Bool);
-                            } else if (optNumberBool == 2) {
-                                nan = isNaN(value1);
-                                nanCmp = m_builder.CreateNot(castValue(arg2, Compiler::StaticType::Bool));
-                            } else {
-                                nan = isNaN(value1);
-                                nanCmp = m_builder.CreateFCmpUGT(value1, value2);
-                            }
-
-                            return m_builder.CreateAnd(m_builder.CreateNot(bothNan), m_builder.CreateSelect(nan, nanCmp, cmp));
-                        }
-
-                        case Comparison::LT: {
-                            llvm::Value *bothNan = m_builder.CreateAnd(isNaN(value1), isNaN(value2)); // NaN == NaN
-                            llvm::Value *cmp = m_builder.CreateFCmpOLT(value1, value2);
-                            llvm::Value *nan;
-                            llvm::Value *nanCmp;
-
-                            if (optNumberBool == 1) {
-                                nan = isNaN(value2);
-                                nanCmp = m_builder.CreateNot(castValue(arg1, Compiler::StaticType::Bool));
-                            } else if (optNumberBool == 2) {
-                                nan = isNaN(value1);
-                                nanCmp = castValue(arg2, Compiler::StaticType::Bool);
-                            } else {
-                                nan = isNaN(value2);
-                                nanCmp = m_builder.CreateFCmpULT(value1, value2);
-                            }
-
-                            return m_builder.CreateAnd(m_builder.CreateNot(bothNan), m_builder.CreateSelect(nan, nanCmp, cmp));
-                        }
-
-                        default:
-                            assert(false);
-                            return nullptr;
-                    }
-                }
-
-                case Compiler::StaticType::Bool:
-                    // Compare two booleans
-                    switch (type) {
-                        case Comparison::EQ:
-                            return m_builder.CreateICmpEQ(value1, value2);
-
-                        case Comparison::GT:
-                            // value1 && !value2
-                            return m_builder.CreateAnd(value1, m_builder.CreateNot(value2));
-
-                        case Comparison::LT:
-                            // value2 && !value1
-                            return m_builder.CreateAnd(value2, m_builder.CreateNot(value1));
-
-                        default:
-                            assert(false);
-                            return nullptr;
-                    }
-
-                case Compiler::StaticType::String: {
-                    // Compare two strings
-                    llvm::Value *cmpRet = m_builder.CreateCall(m_functions.resolve_string_compare_case_insensitive(), { value1, value2 });
-
-                    switch (type) {
-                        case Comparison::EQ:
-                            return m_builder.CreateICmpEQ(cmpRet, m_builder.getInt32(0));
-
-                        case Comparison::GT:
-                            return m_builder.CreateICmpSGT(cmpRet, m_builder.getInt32(0));
-
-                        case Comparison::LT:
-                            return m_builder.CreateICmpSLT(cmpRet, m_builder.getInt32(0));
-
-                        default:
-                            assert(false);
-                            return nullptr;
-                    }
-                }
-
-                default:
-                    assert(false);
-                    return nullptr;
-            }
-        }
-    }
-}
-
-llvm::Value *LLVMCodeBuilder::createStringComparison(LLVMRegister *arg1, LLVMRegister *arg2, bool caseSensitive)
-{
-    auto type1 = arg1->type();
-    auto type2 = arg2->type();
-
-    if (arg1->isConst() && arg2->isConst()) {
-        // If both operands are constant, perform the comparison at compile time
-        StringPtr *str1 = value_toStringPtr(&arg1->constValue().data());
-        StringPtr *str2 = value_toStringPtr(&arg2->constValue().data());
-        bool result;
-
-        if (caseSensitive)
-            result = string_compare_case_sensitive(str1, str2) == 0;
-        else {
-            result = string_compare_case_insensitive(str1, str2) == 0;
-        }
-
-        string_pool_free(str1);
-        string_pool_free(str2);
-        return m_builder.getInt1(result);
-    } else {
-        // Optimize number and string constant comparison
-        // TODO: Optimize bool and string constant comparison (in compare() as well)
-        if ((type1 == Compiler::StaticType::Number && type2 == Compiler::StaticType::String && arg2->isConst() && !arg2->constValue().isValidNumber()) ||
-            (type1 == Compiler::StaticType::String && type2 == Compiler::StaticType::Number && arg1->isConst() && !arg1->constValue().isValidNumber()))
-            return m_builder.getInt1(false);
-
-        // Explicitly cast to string
-        llvm::Value *string1 = castValue(arg1, Compiler::StaticType::String);
-        llvm::Value *string2 = castValue(arg2, Compiler::StaticType::String);
-        llvm::Value *cmp = m_builder.CreateCall(caseSensitive ? m_functions.resolve_string_compare_case_sensitive() : m_functions.resolve_string_compare_case_insensitive(), { string1, string2 });
-        return m_builder.CreateICmpEQ(cmp, m_builder.getInt32(0));
-    }
-}
-
 void LLVMCodeBuilder::createSuspend(LLVMCoroutine *coro, llvm::Value *warpArg, llvm::Value *targetVariables)
 {
     if (!m_warp) {
@@ -2829,9 +1876,9 @@ void LLVMCodeBuilder::createSuspend(LLVMCoroutine *coro, llvm::Value *warpArg, l
             m_builder.SetInsertPoint(suspendBranch);
         }
 
-        syncVariables(targetVariables);
+        m_utils.syncVariables(targetVariables);
         coro->createSuspend();
-        reloadVariables(targetVariables);
+        m_utils.reloadVariables(targetVariables);
 
         if (warpArg) {
             m_builder.CreateBr(nextBranch);
diff --git a/src/engine/internal/llvm/llvmcodebuilder.h b/src/engine/internal/llvm/llvmcodebuilder.h
index 6a831929..4137107c 100644
--- a/src/engine/internal/llvm/llvmcodebuilder.h
+++ b/src/engine/internal/llvm/llvmcodebuilder.h
@@ -10,6 +10,7 @@
 #include <llvm/IR/IRBuilder.h>
 
 #include "../icodebuilder.h"
+#include "llvmbuildutils.h"
 #include "llvminstruction.h"
 #include "llvminstructionlist.h"
 #include "llvmcoroutine.h"
@@ -114,18 +115,7 @@ class LLVMCodeBuilder : public ICodeBuilder
         void createProcedureCall(BlockPrototype *prototype, const Compiler::Args &args) override;
 
     private:
-        enum class Comparison
-        {
-            EQ,
-            GT,
-            LT
-        };
-
         void initTypes();
-        void createVariableMap();
-        void createListMap();
-        void pushScopeLevel();
-        void popScopeLevel();
 
         std::string getMainFunctionName(BlockPrototype *procedurePrototype);
         llvm::FunctionType *getMainFunctionType(BlockPrototype *procedurePrototype);
@@ -134,56 +124,23 @@ class LLVMCodeBuilder : public ICodeBuilder
 
         LLVMRegister *addReg(std::shared_ptr<LLVMRegister> reg, std::shared_ptr<LLVMInstruction> ins);
 
-        llvm::Value *addAlloca(llvm::Type *type);
-        void freeStringLater(llvm::Value *value);
-        void freeScopeHeap();
-        llvm::Value *castValue(LLVMRegister *reg, Compiler::StaticType targetType);
-        llvm::Value *castRawValue(LLVMRegister *reg, Compiler::StaticType targetType);
-        llvm::Constant *castConstValue(const Value &value, Compiler::StaticType targetType);
-        Compiler::StaticType optimizeRegisterType(LLVMRegister *reg) const;
-        llvm::Type *getType(Compiler::StaticType type);
         Compiler::StaticType getProcedureArgType(BlockPrototype::ArgType type);
-        llvm::Value *isNaN(llvm::Value *num);
-        llvm::Value *removeNaN(llvm::Value *num);
-
-        llvm::Value *getVariablePtr(llvm::Value *targetVariables, Variable *variable);
-        llvm::Value *getListPtr(llvm::Value *targetLists, List *list);
-        llvm::Value *getListDataPtr(const LLVMListPtr &listPtr);
-        void syncVariables(llvm::Value *targetVariables);
-        void reloadVariables(llvm::Value *targetVariables);
 
         LLVMRegister *createOp(LLVMInstruction::Type type, Compiler::StaticType retType, Compiler::StaticType argType, const Compiler::Args &args);
         LLVMRegister *createOp(LLVMInstruction::Type type, Compiler::StaticType retType, const Compiler::ArgTypes &argTypes = {}, const Compiler::Args &args = {});
         LLVMRegister *createOp(const LLVMInstruction &ins, Compiler::StaticType retType, Compiler::StaticType argType, const Compiler::Args &args);
         LLVMRegister *createOp(const LLVMInstruction &ins, Compiler::StaticType retType, const Compiler::ArgTypes &argTypes = {}, const Compiler::Args &args = {});
 
-        void createValueStore(LLVMRegister *reg, llvm::Value *targetPtr, Compiler::StaticType sourceType, Compiler::StaticType targetType);
-        void createReusedValueStore(LLVMRegister *reg, llvm::Value *targetPtr, Compiler::StaticType sourceType, Compiler::StaticType targetType);
-        void createValueCopy(llvm::Value *source, llvm::Value *target);
-        void copyStructField(llvm::Value *source, llvm::Value *target, int index, llvm::StructType *structType, llvm::Type *fieldType);
-        llvm::Value *getListItem(const LLVMListPtr &listPtr, llvm::Value *index);
-        llvm::Value *getListItemIndex(const LLVMListPtr &listPtr, Compiler::StaticType listType, LLVMRegister *item);
-        llvm::Value *createValue(LLVMRegister *reg);
-        llvm::Value *createNewValue(LLVMRegister *reg);
-        llvm::Value *createComparison(LLVMRegister *arg1, LLVMRegister *arg2, Comparison type);
-        llvm::Value *createStringComparison(LLVMRegister *arg1, LLVMRegister *arg2, bool caseSensitive);
-
         void createSuspend(LLVMCoroutine *coro, llvm::Value *warpArg, llvm::Value *targetVariables);
 
         Target *m_target = nullptr;
 
-        std::unordered_map<Variable *, size_t> m_targetVariableMap;
-        std::unordered_map<Variable *, LLVMVariablePtr> m_variablePtrs;
-
-        std::unordered_map<List *, size_t> m_targetListMap;
-        std::unordered_map<List *, LLVMListPtr> m_listPtrs;
-
         LLVMCompilerContext *m_ctx;
         llvm::LLVMContext &m_llvmCtx;
         llvm::Module *m_module = nullptr;
         llvm::IRBuilder<> m_builder;
         llvm::Function *m_function = nullptr;
-        LLVMFunctions m_functions;
+        LLVMBuildUtils m_utils;
         LLVMTypeAnalyzer m_typeAnalyzer;
 
         llvm::StructType *m_valueDataType = nullptr;
@@ -200,9 +157,6 @@ class LLVMCodeBuilder : public ICodeBuilder
         Compiler::CodeType m_codeType = Compiler::CodeType::Script;
 
         bool m_loopCondition = false; // whether we're currently compiling a loop condition
-        std::vector<LLVMInstruction *> m_variableInstructions;
-        std::vector<LLVMInstruction *> m_listInstructions;
-        std::vector<std::vector<llvm::Value *>> m_stringHeap; // scopes
 };
 
 } // namespace libscratchcpp

From 41747761fc8956fcf0987578783b5ffb91728e21 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Mon, 4 Aug 2025 13:14:31 +0200
Subject: [PATCH 65/79] LLVMCodeBuilder: Use instruction pointer instead of
 reference

---
 src/engine/internal/llvm/llvmcodebuilder.cpp | 422 +++++++++----------
 1 file changed, 210 insertions(+), 212 deletions(-)

diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp
index 8516752f..60d64f1e 100644
--- a/src/engine/internal/llvm/llvmcodebuilder.cpp
+++ b/src/engine/internal/llvm/llvmcodebuilder.cpp
@@ -99,10 +99,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
     m_utils.init(m_function, targetVariables, targetLists);
 
     // Execute recorded steps
-    for (LLVMInstruction *insPtr = m_instructions.first(); insPtr; insPtr = insPtr->next) {
-        const LLVMInstruction &step = *insPtr;
-
-        switch (step.type) {
+    for (LLVMInstruction *ins = m_instructions.first(); ins; ins = ins->next) {
+        switch (ins->type) {
             case LLVMInstruction::Type::FunctionCall: {
                 std::vector<llvm::Type *> types;
                 std::vector<llvm::Value *> args;
@@ -111,87 +109,87 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 m_utils.syncVariables(targetVariables);
 
                 // Add execution context arg
-                if (step.functionCtxArg) {
+                if (ins->functionCtxArg) {
                     types.push_back(llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0));
                     args.push_back(executionContextPtr);
                 }
 
                 // Add target pointer arg
-                if (step.functionTargetArg) {
+                if (ins->functionTargetArg) {
                     types.push_back(llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0));
                     args.push_back(targetPtr);
                 }
 
                 // Args
-                for (auto &arg : step.args) {
+                for (auto &arg : ins->args) {
                     types.push_back(m_utils.getType(arg.first));
                     args.push_back(m_utils.castValue(arg.second, arg.first));
                 }
 
-                llvm::Type *retType = m_utils.getType(step.functionReturnReg ? step.functionReturnReg->type() : Compiler::StaticType::Void);
-                llvm::Value *ret = m_builder.CreateCall(m_utils.functions().resolveFunction(step.functionName, llvm::FunctionType::get(retType, types, false)), args);
+                llvm::Type *retType = m_utils.getType(ins->functionReturnReg ? ins->functionReturnReg->type() : Compiler::StaticType::Void);
+                llvm::Value *ret = m_builder.CreateCall(m_utils.functions().resolveFunction(ins->functionName, llvm::FunctionType::get(retType, types, false)), args);
 
-                if (step.functionReturnReg) {
-                    step.functionReturnReg->value = ret;
+                if (ins->functionReturnReg) {
+                    ins->functionReturnReg->value = ret;
 
-                    if (step.functionReturnReg->type() == Compiler::StaticType::String)
-                        m_utils.freeStringLater(step.functionReturnReg->value);
+                    if (ins->functionReturnReg->type() == Compiler::StaticType::String)
+                        m_utils.freeStringLater(ins->functionReturnReg->value);
                 }
 
                 break;
             }
 
             case LLVMInstruction::Type::Add: {
-                assert(step.args.size() == 2);
-                const auto &arg1 = step.args[0];
-                const auto &arg2 = step.args[1];
+                assert(ins->args.size() == 2);
+                const auto &arg1 = ins->args[0];
+                const auto &arg2 = ins->args[1];
                 llvm::Value *num1 = m_utils.removeNaN(m_utils.castValue(arg1.second, arg1.first));
                 llvm::Value *num2 = m_utils.removeNaN(m_utils.castValue(arg2.second, arg2.first));
-                step.functionReturnReg->value = m_builder.CreateFAdd(num1, num2);
+                ins->functionReturnReg->value = m_builder.CreateFAdd(num1, num2);
                 break;
             }
 
             case LLVMInstruction::Type::Sub: {
-                assert(step.args.size() == 2);
-                const auto &arg1 = step.args[0];
-                const auto &arg2 = step.args[1];
+                assert(ins->args.size() == 2);
+                const auto &arg1 = ins->args[0];
+                const auto &arg2 = ins->args[1];
                 llvm::Value *num1 = m_utils.removeNaN(m_utils.castValue(arg1.second, arg1.first));
                 llvm::Value *num2 = m_utils.removeNaN(m_utils.castValue(arg2.second, arg2.first));
-                step.functionReturnReg->value = m_builder.CreateFSub(num1, num2);
+                ins->functionReturnReg->value = m_builder.CreateFSub(num1, num2);
                 break;
             }
 
             case LLVMInstruction::Type::Mul: {
-                assert(step.args.size() == 2);
-                const auto &arg1 = step.args[0];
-                const auto &arg2 = step.args[1];
+                assert(ins->args.size() == 2);
+                const auto &arg1 = ins->args[0];
+                const auto &arg2 = ins->args[1];
                 llvm::Value *num1 = m_utils.removeNaN(m_utils.castValue(arg1.second, arg1.first));
                 llvm::Value *num2 = m_utils.removeNaN(m_utils.castValue(arg2.second, arg2.first));
-                step.functionReturnReg->value = m_builder.CreateFMul(num1, num2);
+                ins->functionReturnReg->value = m_builder.CreateFMul(num1, num2);
                 break;
             }
 
             case LLVMInstruction::Type::Div: {
-                assert(step.args.size() == 2);
-                const auto &arg1 = step.args[0];
-                const auto &arg2 = step.args[1];
+                assert(ins->args.size() == 2);
+                const auto &arg1 = ins->args[0];
+                const auto &arg2 = ins->args[1];
                 llvm::Value *num1 = m_utils.removeNaN(m_utils.castValue(arg1.second, arg1.first));
                 llvm::Value *num2 = m_utils.removeNaN(m_utils.castValue(arg2.second, arg2.first));
-                step.functionReturnReg->value = m_builder.CreateFDiv(num1, num2);
+                ins->functionReturnReg->value = m_builder.CreateFDiv(num1, num2);
                 break;
             }
 
             case LLVMInstruction::Type::Random: {
-                assert(step.args.size() == 2);
-                const auto &arg1 = step.args[0];
-                const auto &arg2 = step.args[1];
+                assert(ins->args.size() == 2);
+                const auto &arg1 = ins->args[0];
+                const auto &arg2 = ins->args[1];
                 LLVMRegister *reg1 = arg1.second;
                 LLVMRegister *reg2 = arg2.second;
 
                 if (reg1->type() == Compiler::StaticType::Bool && reg2->type() == Compiler::StaticType::Bool) {
                     llvm::Value *bool1 = m_utils.castValue(arg1.second, Compiler::StaticType::Bool);
                     llvm::Value *bool2 = m_utils.castValue(arg2.second, Compiler::StaticType::Bool);
-                    step.functionReturnReg->value = m_builder.CreateCall(m_utils.functions().resolve_llvm_random_bool(), { executionContextPtr, bool1, bool2 });
+                    ins->functionReturnReg->value = m_builder.CreateCall(m_utils.functions().resolve_llvm_random_bool(), { executionContextPtr, bool1, bool2 });
                 } else {
                     llvm::Constant *inf = llvm::ConstantFP::getInfinity(m_builder.getDoubleTy(), false);
                     llvm::Value *num1 = m_utils.removeNaN(m_utils.castValue(arg1.second, Compiler::StaticType::Number));
@@ -202,12 +200,12 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
                     // NOTE: The random function will be called even in edge cases where it isn't needed, but they're rare, so it shouldn't be an issue
                     if (reg1->type() == Compiler::StaticType::Number && reg2->type() == Compiler::StaticType::Number)
-                        step.functionReturnReg->value =
+                        ins->functionReturnReg->value =
                             m_builder.CreateSelect(isInfOrNaN, sum, m_builder.CreateCall(m_utils.functions().resolve_llvm_random_double(), { executionContextPtr, num1, num2 }));
                     else {
                         llvm::Value *value1 = m_utils.createValue(reg1);
                         llvm::Value *value2 = m_utils.createValue(reg2);
-                        step.functionReturnReg->value =
+                        ins->functionReturnReg->value =
                             m_builder.CreateSelect(isInfOrNaN, sum, m_builder.CreateCall(m_utils.functions().resolve_llvm_random(), { executionContextPtr, value1, value2 }));
                     }
                 }
@@ -216,100 +214,100 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
             }
 
             case LLVMInstruction::Type::RandomInt: {
-                assert(step.args.size() == 2);
-                const auto &arg1 = step.args[0];
-                const auto &arg2 = step.args[1];
+                assert(ins->args.size() == 2);
+                const auto &arg1 = ins->args[0];
+                const auto &arg2 = ins->args[1];
                 llvm::Value *from = m_builder.CreateFPToSI(m_utils.castValue(arg1.second, arg1.first), m_builder.getInt64Ty());
                 llvm::Value *to = m_builder.CreateFPToSI(m_utils.castValue(arg2.second, arg2.first), m_builder.getInt64Ty());
-                step.functionReturnReg->value = m_builder.CreateCall(m_utils.functions().resolve_llvm_random_long(), { executionContextPtr, from, to });
+                ins->functionReturnReg->value = m_builder.CreateCall(m_utils.functions().resolve_llvm_random_long(), { executionContextPtr, from, to });
                 break;
             }
 
             case LLVMInstruction::Type::CmpEQ: {
-                assert(step.args.size() == 2);
-                const auto &arg1 = step.args[0].second;
-                const auto &arg2 = step.args[1].second;
-                step.functionReturnReg->value = m_utils.createComparison(arg1, arg2, LLVMBuildUtils::Comparison::EQ);
+                assert(ins->args.size() == 2);
+                const auto &arg1 = ins->args[0].second;
+                const auto &arg2 = ins->args[1].second;
+                ins->functionReturnReg->value = m_utils.createComparison(arg1, arg2, LLVMBuildUtils::Comparison::EQ);
                 break;
             }
 
             case LLVMInstruction::Type::CmpGT: {
-                assert(step.args.size() == 2);
-                const auto &arg1 = step.args[0].second;
-                const auto &arg2 = step.args[1].second;
-                step.functionReturnReg->value = m_utils.createComparison(arg1, arg2, LLVMBuildUtils::Comparison::GT);
+                assert(ins->args.size() == 2);
+                const auto &arg1 = ins->args[0].second;
+                const auto &arg2 = ins->args[1].second;
+                ins->functionReturnReg->value = m_utils.createComparison(arg1, arg2, LLVMBuildUtils::Comparison::GT);
                 break;
             }
 
             case LLVMInstruction::Type::CmpLT: {
-                assert(step.args.size() == 2);
-                const auto &arg1 = step.args[0].second;
-                const auto &arg2 = step.args[1].second;
-                step.functionReturnReg->value = m_utils.createComparison(arg1, arg2, LLVMBuildUtils::Comparison::LT);
+                assert(ins->args.size() == 2);
+                const auto &arg1 = ins->args[0].second;
+                const auto &arg2 = ins->args[1].second;
+                ins->functionReturnReg->value = m_utils.createComparison(arg1, arg2, LLVMBuildUtils::Comparison::LT);
                 break;
             }
 
             case LLVMInstruction::Type::StrCmpEQCS: {
-                assert(step.args.size() == 2);
-                const auto &arg1 = step.args[0].second;
-                const auto &arg2 = step.args[1].second;
-                step.functionReturnReg->value = m_utils.createStringComparison(arg1, arg2, true);
+                assert(ins->args.size() == 2);
+                const auto &arg1 = ins->args[0].second;
+                const auto &arg2 = ins->args[1].second;
+                ins->functionReturnReg->value = m_utils.createStringComparison(arg1, arg2, true);
                 break;
             }
 
             case LLVMInstruction::Type::StrCmpEQCI: {
-                assert(step.args.size() == 2);
-                const auto &arg1 = step.args[0].second;
-                const auto &arg2 = step.args[1].second;
-                step.functionReturnReg->value = m_utils.createStringComparison(arg1, arg2, false);
+                assert(ins->args.size() == 2);
+                const auto &arg1 = ins->args[0].second;
+                const auto &arg2 = ins->args[1].second;
+                ins->functionReturnReg->value = m_utils.createStringComparison(arg1, arg2, false);
                 break;
             }
 
             case LLVMInstruction::Type::And: {
-                assert(step.args.size() == 2);
-                const auto &arg1 = step.args[0];
-                const auto &arg2 = step.args[1];
+                assert(ins->args.size() == 2);
+                const auto &arg1 = ins->args[0];
+                const auto &arg2 = ins->args[1];
                 llvm::Value *bool1 = m_utils.castValue(arg1.second, arg1.first);
                 llvm::Value *bool2 = m_utils.castValue(arg2.second, arg2.first);
-                step.functionReturnReg->value = m_builder.CreateAnd(bool1, bool2);
+                ins->functionReturnReg->value = m_builder.CreateAnd(bool1, bool2);
                 break;
             }
 
             case LLVMInstruction::Type::Or: {
-                assert(step.args.size() == 2);
-                const auto &arg1 = step.args[0];
-                const auto &arg2 = step.args[1];
+                assert(ins->args.size() == 2);
+                const auto &arg1 = ins->args[0];
+                const auto &arg2 = ins->args[1];
                 llvm::Value *bool1 = m_utils.castValue(arg1.second, arg1.first);
                 llvm::Value *bool2 = m_utils.castValue(arg2.second, arg2.first);
-                step.functionReturnReg->value = m_builder.CreateOr(bool1, bool2);
+                ins->functionReturnReg->value = m_builder.CreateOr(bool1, bool2);
                 break;
             }
 
             case LLVMInstruction::Type::Not: {
-                assert(step.args.size() == 1);
-                const auto &arg = step.args[0];
+                assert(ins->args.size() == 1);
+                const auto &arg = ins->args[0];
                 llvm::Value *value = m_utils.castValue(arg.second, arg.first);
-                step.functionReturnReg->value = m_builder.CreateNot(value);
+                ins->functionReturnReg->value = m_builder.CreateNot(value);
                 break;
             }
 
             case LLVMInstruction::Type::Mod: {
-                assert(step.args.size() == 2);
-                const auto &arg1 = step.args[0];
-                const auto &arg2 = step.args[1];
+                assert(ins->args.size() == 2);
+                const auto &arg1 = ins->args[0];
+                const auto &arg2 = ins->args[1];
                 // rem(a, b) / b < 0.0 ? rem(a, b) + b : rem(a, b)
                 llvm::Constant *zero = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0));
                 llvm::Value *num1 = m_utils.removeNaN(m_utils.castValue(arg1.second, arg1.first));
                 llvm::Value *num2 = m_utils.removeNaN(m_utils.castValue(arg2.second, arg2.first));
                 llvm::Value *value = m_builder.CreateFRem(num1, num2);                                // rem(a, b)
                 llvm::Value *cond = m_builder.CreateFCmpOLT(m_builder.CreateFDiv(value, num2), zero); // rem(a, b) / b < 0.0                                                            // rem(a, b)
-                step.functionReturnReg->value = m_builder.CreateSelect(cond, m_builder.CreateFAdd(value, num2), value);
+                ins->functionReturnReg->value = m_builder.CreateSelect(cond, m_builder.CreateFAdd(value, num2), value);
                 break;
             }
 
             case LLVMInstruction::Type::Round: {
-                assert(step.args.size() == 1);
-                const auto &arg = step.args[0];
+                assert(ins->args.size() == 1);
+                const auto &arg = ins->args[0];
                 // x >= 0.0 ? round(x) : (x >= -0.5 ? -0.0 : floor(x + 0.5))
                 llvm::Constant *zero = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0));
                 llvm::Constant *negativeZero = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(-0.0));
@@ -320,52 +318,52 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Value *roundNum = m_builder.CreateCall(roundFunc, num);                                                                                  // round(num)
                 llvm::Value *negativeCond = m_builder.CreateFCmpOGE(num, llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(-0.5)));                               // num >= -0.5
                 llvm::Value *negativeRound = m_builder.CreateCall(floorFunc, m_builder.CreateFAdd(num, llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.5)))); // floor(x + 0.5)
-                step.functionReturnReg->value = m_builder.CreateSelect(notNegative, roundNum, m_builder.CreateSelect(negativeCond, negativeZero, negativeRound));
+                ins->functionReturnReg->value = m_builder.CreateSelect(notNegative, roundNum, m_builder.CreateSelect(negativeCond, negativeZero, negativeRound));
                 break;
             }
 
             case LLVMInstruction::Type::Abs: {
-                assert(step.args.size() == 1);
-                const auto &arg = step.args[0];
+                assert(ins->args.size() == 1);
+                const auto &arg = ins->args[0];
                 llvm::Function *absFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::fabs, m_builder.getDoubleTy());
                 llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
-                step.functionReturnReg->value = m_builder.CreateCall(absFunc, num);
+                ins->functionReturnReg->value = m_builder.CreateCall(absFunc, num);
                 break;
             }
 
             case LLVMInstruction::Type::Floor: {
-                assert(step.args.size() == 1);
-                const auto &arg = step.args[0];
+                assert(ins->args.size() == 1);
+                const auto &arg = ins->args[0];
                 llvm::Function *floorFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::floor, m_builder.getDoubleTy());
                 llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
-                step.functionReturnReg->value = m_builder.CreateCall(floorFunc, num);
+                ins->functionReturnReg->value = m_builder.CreateCall(floorFunc, num);
                 break;
             }
 
             case LLVMInstruction::Type::Ceil: {
-                assert(step.args.size() == 1);
-                const auto &arg = step.args[0];
+                assert(ins->args.size() == 1);
+                const auto &arg = ins->args[0];
                 llvm::Function *ceilFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::ceil, m_builder.getDoubleTy());
                 llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
-                step.functionReturnReg->value = m_builder.CreateCall(ceilFunc, num);
+                ins->functionReturnReg->value = m_builder.CreateCall(ceilFunc, num);
                 break;
             }
 
             case LLVMInstruction::Type::Sqrt: {
-                assert(step.args.size() == 1);
-                const auto &arg = step.args[0];
+                assert(ins->args.size() == 1);
+                const auto &arg = ins->args[0];
                 // sqrt(x) + 0.0
                 // This avoids negative zero
                 llvm::Constant *zero = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0));
                 llvm::Function *sqrtFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::sqrt, m_builder.getDoubleTy());
                 llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
-                step.functionReturnReg->value = m_builder.CreateFAdd(m_builder.CreateCall(sqrtFunc, num), zero);
+                ins->functionReturnReg->value = m_builder.CreateFAdd(m_builder.CreateCall(sqrtFunc, num), zero);
                 break;
             }
 
             case LLVMInstruction::Type::Sin: {
-                assert(step.args.size() == 1);
-                const auto &arg = step.args[0];
+                assert(ins->args.size() == 1);
+                const auto &arg = ins->args[0];
                 // round(sin(x * pi / 180.0) * 1e10) / 1e10 + 0.0
                 // +0.0 to avoid -0.0
                 llvm::Constant *zero = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0));
@@ -377,13 +375,13 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
                 llvm::Value *sinResult = m_builder.CreateCall(sinFunc, m_builder.CreateFDiv(m_builder.CreateFMul(num, pi), piDeg)); // sin(x * pi / 180)
                 llvm::Value *rounded = m_builder.CreateCall(roundFunc, m_builder.CreateFMul(sinResult, factor));                    // round(sin(x * 180) * 1e10)
-                step.functionReturnReg->value = m_builder.CreateFAdd(m_builder.CreateFDiv(rounded, factor), zero);
+                ins->functionReturnReg->value = m_builder.CreateFAdd(m_builder.CreateFDiv(rounded, factor), zero);
                 break;
             }
 
             case LLVMInstruction::Type::Cos: {
-                assert(step.args.size() == 1);
-                const auto &arg = step.args[0];
+                assert(ins->args.size() == 1);
+                const auto &arg = ins->args[0];
                 // round(cos(x * pi / 180.0) * 1e10) / 1e10
                 llvm::Constant *pi = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(std::acos(-1.0)));
                 llvm::Constant *piDeg = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(180.0));
@@ -393,13 +391,13 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
                 llvm::Value *cosResult = m_builder.CreateCall(cosFunc, m_builder.CreateFDiv(m_builder.CreateFMul(num, pi), piDeg)); // cos(x * pi / 180)
                 llvm::Value *rounded = m_builder.CreateCall(roundFunc, m_builder.CreateFMul(cosResult, factor));                    // round(cos(x * 180) * 1e10)
-                step.functionReturnReg->value = m_builder.CreateFDiv(rounded, factor);
+                ins->functionReturnReg->value = m_builder.CreateFDiv(rounded, factor);
                 break;
             }
 
             case LLVMInstruction::Type::Tan: {
-                assert(step.args.size() == 1);
-                const auto &arg = step.args[0];
+                assert(ins->args.size() == 1);
+                const auto &arg = ins->args[0];
                 // ((mod = rem(x, 360.0)) == -270.0 || mod == 90.0) ? inf : ((mod == -90.0 || mod == 270.0) ? -inf : round(tan(x * pi / 180.0) * 1e10) / 1e10 + 0.0)
                 // +0.0 to avoid -0.0
                 llvm::Constant *zero = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0));
@@ -425,13 +423,13 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Value *rounded = m_builder.CreateCall(roundFunc, m_builder.CreateFMul(tanResult, factor));                    // round(tan(x * 180) * 1e10)
                 llvm::Value *result = m_builder.CreateFAdd(m_builder.CreateFDiv(rounded, factor), zero);                            // round(tan(x * pi / 180.0) * 1e10) / 1e10 + 0.0
                 llvm::Value *inner = m_builder.CreateSelect(m_builder.CreateOr(isUndefined3, isUndefined4), negInf, result);
-                step.functionReturnReg->value = m_builder.CreateSelect(m_builder.CreateOr(isUndefined1, isUndefined2), posInf, inner);
+                ins->functionReturnReg->value = m_builder.CreateSelect(m_builder.CreateOr(isUndefined1, isUndefined2), posInf, inner);
                 break;
             }
 
             case LLVMInstruction::Type::Asin: {
-                assert(step.args.size() == 1);
-                const auto &arg = step.args[0];
+                assert(ins->args.size() == 1);
+                const auto &arg = ins->args[0];
                 // asin(x) * 180.0 / pi + 0.0
                 // +0.0 to avoid -0.0
                 llvm::Constant *zero = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0));
@@ -439,78 +437,78 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Constant *piDeg = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(180.0));
                 llvm::Function *asinFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::asin, m_builder.getDoubleTy());
                 llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
-                step.functionReturnReg->value = m_builder.CreateFAdd(m_builder.CreateFDiv(m_builder.CreateFMul(m_builder.CreateCall(asinFunc, num), piDeg), pi), zero);
+                ins->functionReturnReg->value = m_builder.CreateFAdd(m_builder.CreateFDiv(m_builder.CreateFMul(m_builder.CreateCall(asinFunc, num), piDeg), pi), zero);
                 break;
             }
 
             case LLVMInstruction::Type::Acos: {
-                assert(step.args.size() == 1);
-                const auto &arg = step.args[0];
+                assert(ins->args.size() == 1);
+                const auto &arg = ins->args[0];
                 // acos(x) * 180.0 / pi
                 llvm::Constant *pi = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(std::acos(-1.0)));
                 llvm::Constant *piDeg = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(180.0));
                 llvm::Function *acosFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::acos, m_builder.getDoubleTy());
                 llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
-                step.functionReturnReg->value = m_builder.CreateFDiv(m_builder.CreateFMul(m_builder.CreateCall(acosFunc, num), piDeg), pi);
+                ins->functionReturnReg->value = m_builder.CreateFDiv(m_builder.CreateFMul(m_builder.CreateCall(acosFunc, num), piDeg), pi);
                 break;
             }
 
             case LLVMInstruction::Type::Atan: {
-                assert(step.args.size() == 1);
-                const auto &arg = step.args[0];
+                assert(ins->args.size() == 1);
+                const auto &arg = ins->args[0];
                 // atan(x) * 180.0 / pi
                 llvm::Constant *pi = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(std::acos(-1.0)));
                 llvm::Constant *piDeg = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(180.0));
                 llvm::Function *atanFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::atan, m_builder.getDoubleTy());
                 llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
-                step.functionReturnReg->value = m_builder.CreateFDiv(m_builder.CreateFMul(m_builder.CreateCall(atanFunc, num), piDeg), pi);
+                ins->functionReturnReg->value = m_builder.CreateFDiv(m_builder.CreateFMul(m_builder.CreateCall(atanFunc, num), piDeg), pi);
                 break;
             }
 
             case LLVMInstruction::Type::Ln: {
-                assert(step.args.size() == 1);
-                const auto &arg = step.args[0];
+                assert(ins->args.size() == 1);
+                const auto &arg = ins->args[0];
                 // log(x)
                 llvm::Function *logFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::log, m_builder.getDoubleTy());
                 llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
-                step.functionReturnReg->value = m_builder.CreateCall(logFunc, num);
+                ins->functionReturnReg->value = m_builder.CreateCall(logFunc, num);
                 break;
             }
 
             case LLVMInstruction::Type::Log10: {
-                assert(step.args.size() == 1);
-                const auto &arg = step.args[0];
+                assert(ins->args.size() == 1);
+                const auto &arg = ins->args[0];
                 // log10(x)
                 llvm::Function *log10Func = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::log10, m_builder.getDoubleTy());
                 llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
-                step.functionReturnReg->value = m_builder.CreateCall(log10Func, num);
+                ins->functionReturnReg->value = m_builder.CreateCall(log10Func, num);
                 break;
             }
 
             case LLVMInstruction::Type::Exp: {
-                assert(step.args.size() == 1);
-                const auto &arg = step.args[0];
+                assert(ins->args.size() == 1);
+                const auto &arg = ins->args[0];
                 // exp(x)
                 llvm::Function *expFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::exp, m_builder.getDoubleTy());
                 llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
-                step.functionReturnReg->value = m_builder.CreateCall(expFunc, num);
+                ins->functionReturnReg->value = m_builder.CreateCall(expFunc, num);
                 break;
             }
 
             case LLVMInstruction::Type::Exp10: {
-                assert(step.args.size() == 1);
-                const auto &arg = step.args[0];
+                assert(ins->args.size() == 1);
+                const auto &arg = ins->args[0];
                 // exp10(x)
                 llvm::Function *expFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::exp10, m_builder.getDoubleTy());
                 llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
-                step.functionReturnReg->value = m_builder.CreateCall(expFunc, num);
+                ins->functionReturnReg->value = m_builder.CreateCall(expFunc, num);
                 break;
             }
 
             case LLVMInstruction::Type::StringConcat: {
-                assert(step.args.size() == 2);
-                const auto &arg1 = step.args[0];
-                const auto &arg2 = step.args[1];
+                assert(ins->args.size() == 2);
+                const auto &arg1 = ins->args[0];
+                const auto &arg2 = ins->args[1];
                 llvm::Value *str1 = m_utils.castValue(arg1.second, arg1.first);
                 llvm::Value *str2 = m_utils.castValue(arg2.second, arg2.first);
                 llvm::PointerType *charPointerType = m_builder.getInt16Ty()->getPointerTo();
@@ -546,14 +544,14 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 writePtr = m_builder.CreateGEP(m_builder.getInt16Ty(), writePtr, size1);
                 m_builder.CreateCall(memcpyFunc, { writePtr, data2, m_builder.CreateMul(m_builder.CreateAdd(size2, m_builder.getInt64(1)), m_builder.getInt64(2)), m_builder.getInt1(false) });
 
-                step.functionReturnReg->value = result;
+                ins->functionReturnReg->value = result;
                 break;
             }
 
             case LLVMInstruction::Type::StringChar: {
-                assert(step.args.size() == 2);
-                const auto &arg1 = step.args[0];
-                const auto &arg2 = step.args[1];
+                assert(ins->args.size() == 2);
+                const auto &arg1 = ins->args[0];
+                const auto &arg2 = ins->args[1];
                 llvm::Value *str = m_utils.castValue(arg1.second, arg1.first);
                 llvm::Value *index = m_builder.CreateFPToSI(m_utils.castValue(arg2.second, arg2.first), m_builder.getInt64Ty());
                 llvm::PointerType *charPointerType = m_builder.getInt16Ty()->getPointerTo();
@@ -585,25 +583,25 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 m_builder.CreateStore(m_builder.getInt16(0), char2);
                 m_builder.CreateStore(m_builder.CreateSelect(inRange, m_builder.getInt64(1), m_builder.getInt64(0)), sizeField);
 
-                step.functionReturnReg->value = result;
+                ins->functionReturnReg->value = result;
                 break;
             }
 
             case LLVMInstruction::Type::StringLength: {
-                assert(step.args.size() == 1);
-                const auto &arg = step.args[0];
+                assert(ins->args.size() == 1);
+                const auto &arg = ins->args[0];
                 llvm::Value *str = m_utils.castValue(arg.second, arg.first);
                 llvm::Value *sizeField = m_builder.CreateStructGEP(m_stringPtrType, str, 1);
                 llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), sizeField);
-                step.functionReturnReg->value = m_builder.CreateSIToFP(size, m_builder.getDoubleTy());
+                ins->functionReturnReg->value = m_builder.CreateSIToFP(size, m_builder.getDoubleTy());
                 break;
             }
 
             case LLVMInstruction::Type::Select: {
-                assert(step.args.size() == 3);
-                const auto &arg1 = step.args[0];
-                const auto &arg2 = step.args[1];
-                const auto &arg3 = step.args[2];
+                assert(ins->args.size() == 3);
+                const auto &arg1 = ins->args[0];
+                const auto &arg2 = ins->args[1];
+                const auto &arg3 = ins->args[2];
                 auto type = arg2.first;
                 llvm::Value *cond = m_utils.castValue(arg1.second, arg1.first);
                 llvm::Value *trueValue;
@@ -617,15 +615,15 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                     falseValue = m_utils.castValue(arg3.second, type);
                 }
 
-                step.functionReturnReg->value = m_builder.CreateSelect(cond, trueValue, falseValue);
+                ins->functionReturnReg->value = m_builder.CreateSelect(cond, trueValue, falseValue);
                 break;
             }
 
             case LLVMInstruction::Type::CreateLocalVariable: {
-                assert(step.args.empty());
+                assert(ins->args.empty());
                 llvm::Type *type = nullptr;
 
-                switch (step.functionReturnReg->type()) {
+                switch (ins->functionReturnReg->type()) {
                     case Compiler::StaticType::Number:
                         type = m_builder.getDoubleTy();
                         break;
@@ -647,25 +645,25 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                         break;
                 }
 
-                step.functionReturnReg->value = m_utils.addAlloca(type);
+                ins->functionReturnReg->value = m_utils.addAlloca(type);
                 break;
             }
 
             case LLVMInstruction::Type::WriteLocalVariable: {
-                assert(step.args.size() == 2);
-                const auto &arg1 = step.args[0];
-                const auto &arg2 = step.args[1];
+                assert(ins->args.size() == 2);
+                const auto &arg1 = ins->args[0];
+                const auto &arg2 = ins->args[1];
                 llvm::Value *converted = m_utils.castValue(arg2.second, arg2.first);
                 m_builder.CreateStore(converted, arg1.second->value);
                 break;
             }
 
             case LLVMInstruction::Type::ReadLocalVariable: {
-                assert(step.args.size() == 1);
-                const auto &arg = step.args[0];
+                assert(ins->args.size() == 1);
+                const auto &arg = ins->args[0];
                 llvm::Type *type = nullptr;
 
-                switch (step.functionReturnReg->type()) {
+                switch (ins->functionReturnReg->type()) {
                     case Compiler::StaticType::Number:
                         type = m_builder.getDoubleTy();
                         break;
@@ -679,21 +677,21 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                         break;
                 }
 
-                step.functionReturnReg->value = m_builder.CreateLoad(type, arg.second->value);
+                ins->functionReturnReg->value = m_builder.CreateLoad(type, arg.second->value);
                 break;
             }
 
             case LLVMInstruction::Type::WriteVariable: {
-                assert(step.args.size() == 1);
-                const auto &arg = step.args[0];
+                assert(ins->args.size() == 1);
+                const auto &arg = ins->args[0];
                 Compiler::StaticType argType = m_utils.optimizeRegisterType(arg.second);
-                LLVMVariablePtr &varPtr = m_utils.variablePtr(step.workVariable);
+                LLVMVariablePtr &varPtr = m_utils.variablePtr(ins->workVariable);
                 varPtr.changed = true; // TODO: Handle loops and if statements
 
                 Compiler::StaticType varType = Compiler::StaticType::Unknown;
 
                 if (m_warp)
-                    varType = m_typeAnalyzer.variableType(step.workVariable, &step, Compiler::StaticType::Unknown);
+                    varType = m_typeAnalyzer.variableType(ins->workVariable, ins, Compiler::StaticType::Unknown);
 
                 // Initialize stack variable on first assignment
                 // TODO: Use stack in the top level (outside loops and if statements)
@@ -721,29 +719,29 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
             }
 
             case LLVMInstruction::Type::ReadVariable: {
-                assert(step.args.size() == 0);
-                LLVMVariablePtr &varPtr = m_utils.variablePtr(step.workVariable);
+                assert(ins->args.size() == 0);
+                LLVMVariablePtr &varPtr = m_utils.variablePtr(ins->workVariable);
                 Compiler::StaticType type = Compiler::StaticType::Unknown;
 
                 if (m_warp)
-                    type = m_typeAnalyzer.variableType(step.workVariable, &step, Compiler::StaticType::Unknown);
+                    type = m_typeAnalyzer.variableType(ins->workVariable, ins, Compiler::StaticType::Unknown);
 
-                step.functionReturnReg->value = varPtr.onStack && !(step.loopCondition && !m_warp) ? varPtr.stackPtr : varPtr.heapPtr;
-                step.functionReturnReg->setType(type);
+                ins->functionReturnReg->value = varPtr.onStack && !(ins->loopCondition && !m_warp) ? varPtr.stackPtr : varPtr.heapPtr;
+                ins->functionReturnReg->setType(type);
                 break;
             }
 
             case LLVMInstruction::Type::ClearList: {
-                assert(step.args.size() == 0);
-                LLVMListPtr &listPtr = m_utils.listPtr(step.workList);
+                assert(ins->args.size() == 0);
+                LLVMListPtr &listPtr = m_utils.listPtr(ins->workList);
                 m_builder.CreateCall(m_utils.functions().resolve_list_clear(), listPtr.ptr);
                 break;
             }
 
             case LLVMInstruction::Type::RemoveListItem: {
-                assert(step.args.size() == 1);
-                const auto &arg = step.args[0];
-                LLVMListPtr &listPtr = m_utils.listPtr(step.workList);
+                assert(ins->args.size() == 1);
+                const auto &arg = ins->args[0];
+                LLVMListPtr &listPtr = m_utils.listPtr(ins->workList);
 
                 // Range check
                 llvm::Value *min = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0));
@@ -766,15 +764,15 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
             }
 
             case LLVMInstruction::Type::AppendToList: {
-                assert(step.args.size() == 1);
-                const auto &arg = step.args[0];
+                assert(ins->args.size() == 1);
+                const auto &arg = ins->args[0];
                 Compiler::StaticType type = m_utils.optimizeRegisterType(arg.second);
-                LLVMListPtr &listPtr = m_utils.listPtr(step.workList);
+                LLVMListPtr &listPtr = m_utils.listPtr(ins->workList);
 
                 Compiler::StaticType listType = Compiler::StaticType::Unknown;
 
                 if (m_warp)
-                    listType = m_typeAnalyzer.listType(step.workList, &step, Compiler::StaticType::Unknown, false);
+                    listType = m_typeAnalyzer.listType(ins->workList, ins, Compiler::StaticType::Unknown, false);
 
                 // Check if enough space is allocated
                 llvm::Value *allocatedSize = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.allocatedSizePtr);
@@ -804,16 +802,16 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
             }
 
             case LLVMInstruction::Type::InsertToList: {
-                assert(step.args.size() == 2);
-                const auto &indexArg = step.args[0];
-                const auto &valueArg = step.args[1];
+                assert(ins->args.size() == 2);
+                const auto &indexArg = ins->args[0];
+                const auto &valueArg = ins->args[1];
                 Compiler::StaticType type = m_utils.optimizeRegisterType(valueArg.second);
-                LLVMListPtr &listPtr = m_utils.listPtr(step.workList);
+                LLVMListPtr &listPtr = m_utils.listPtr(ins->workList);
 
                 Compiler::StaticType listType = Compiler::StaticType::Unknown;
 
                 if (m_warp)
-                    listType = m_typeAnalyzer.listType(step.workList, &step, Compiler::StaticType::Unknown, false);
+                    listType = m_typeAnalyzer.listType(ins->workList, ins, Compiler::StaticType::Unknown, false);
 
                 // Range check
                 llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.sizePtr);
@@ -838,16 +836,16 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
             }
 
             case LLVMInstruction::Type::ListReplace: {
-                assert(step.args.size() == 2);
-                const auto &indexArg = step.args[0];
-                const auto &valueArg = step.args[1];
+                assert(ins->args.size() == 2);
+                const auto &indexArg = ins->args[0];
+                const auto &valueArg = ins->args[1];
                 Compiler::StaticType type = m_utils.optimizeRegisterType(valueArg.second);
-                LLVMListPtr &listPtr = m_utils.listPtr(step.workList);
+                LLVMListPtr &listPtr = m_utils.listPtr(ins->workList);
 
                 Compiler::StaticType listType = Compiler::StaticType::Unknown;
 
                 if (m_warp)
-                    listType = m_typeAnalyzer.listType(step.workList, &step, Compiler::StaticType::Unknown, false);
+                    listType = m_typeAnalyzer.listType(ins->workList, ins, Compiler::StaticType::Unknown, false);
 
                 // Range check
                 llvm::Value *min = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0));
@@ -871,23 +869,23 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
             }
 
             case LLVMInstruction::Type::GetListContents: {
-                assert(step.args.size() == 0);
-                const LLVMListPtr &listPtr = m_utils.listPtr(step.workList);
+                assert(ins->args.size() == 0);
+                const LLVMListPtr &listPtr = m_utils.listPtr(ins->workList);
                 llvm::Value *ptr = m_builder.CreateCall(m_utils.functions().resolve_list_to_string(), listPtr.ptr);
                 m_utils.freeStringLater(ptr);
-                step.functionReturnReg->value = ptr;
+                ins->functionReturnReg->value = ptr;
                 break;
             }
 
             case LLVMInstruction::Type::GetListItem: {
-                assert(step.args.size() == 1);
-                const auto &arg = step.args[0];
-                LLVMListPtr &listPtr = m_utils.listPtr(step.workList);
+                assert(ins->args.size() == 1);
+                const auto &arg = ins->args[0];
+                LLVMListPtr &listPtr = m_utils.listPtr(ins->workList);
 
                 Compiler::StaticType listType = Compiler::StaticType::Unknown;
 
                 if (m_warp)
-                    listType = m_typeAnalyzer.listType(step.workList, &step, Compiler::StaticType::Unknown, false);
+                    listType = m_typeAnalyzer.listType(ins->workList, ins, Compiler::StaticType::Unknown, false);
 
                 llvm::Value *min = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0));
                 llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.sizePtr);
@@ -899,45 +897,45 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Value *null = m_utils.createValue(static_cast<LLVMRegister *>(&nullReg));
 
                 index = m_builder.CreateFPToUI(index, m_builder.getInt64Ty());
-                step.functionReturnReg->value = m_builder.CreateSelect(inRange, m_utils.getListItem(listPtr, index), null);
-                step.functionReturnReg->setType(listType);
+                ins->functionReturnReg->value = m_builder.CreateSelect(inRange, m_utils.getListItem(listPtr, index), null);
+                ins->functionReturnReg->setType(listType);
                 break;
             }
 
             case LLVMInstruction::Type::GetListSize: {
-                assert(step.args.size() == 0);
-                const LLVMListPtr &listPtr = m_utils.listPtr(step.workList);
+                assert(ins->args.size() == 0);
+                const LLVMListPtr &listPtr = m_utils.listPtr(ins->workList);
                 llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.sizePtr);
-                step.functionReturnReg->value = m_builder.CreateUIToFP(size, m_builder.getDoubleTy());
+                ins->functionReturnReg->value = m_builder.CreateUIToFP(size, m_builder.getDoubleTy());
                 break;
             }
 
             case LLVMInstruction::Type::GetListItemIndex: {
-                assert(step.args.size() == 1);
-                const auto &arg = step.args[0];
-                LLVMListPtr &listPtr = m_utils.listPtr(step.workList);
+                assert(ins->args.size() == 1);
+                const auto &arg = ins->args[0];
+                LLVMListPtr &listPtr = m_utils.listPtr(ins->workList);
 
                 Compiler::StaticType listType = Compiler::StaticType::Unknown;
 
                 if (m_warp)
-                    listType = m_typeAnalyzer.listType(step.workList, &step, Compiler::StaticType::Unknown, false);
+                    listType = m_typeAnalyzer.listType(ins->workList, ins, Compiler::StaticType::Unknown, false);
 
-                step.functionReturnReg->value = m_builder.CreateSIToFP(m_utils.getListItemIndex(listPtr, listType, arg.second), m_builder.getDoubleTy());
+                ins->functionReturnReg->value = m_builder.CreateSIToFP(m_utils.getListItemIndex(listPtr, listType, arg.second), m_builder.getDoubleTy());
                 break;
             }
 
             case LLVMInstruction::Type::ListContainsItem: {
-                assert(step.args.size() == 1);
-                const auto &arg = step.args[0];
-                LLVMListPtr &listPtr = m_utils.listPtr(step.workList);
+                assert(ins->args.size() == 1);
+                const auto &arg = ins->args[0];
+                LLVMListPtr &listPtr = m_utils.listPtr(ins->workList);
 
                 Compiler::StaticType listType = Compiler::StaticType::Unknown;
 
                 if (m_warp)
-                    listType = m_typeAnalyzer.listType(step.workList, &step, Compiler::StaticType::Unknown, false);
+                    listType = m_typeAnalyzer.listType(ins->workList, ins, Compiler::StaticType::Unknown, false);
 
                 llvm::Value *index = m_utils.getListItemIndex(listPtr, listType, arg.second);
-                step.functionReturnReg->value = m_builder.CreateICmpSGT(index, llvm::ConstantInt::get(m_builder.getInt64Ty(), -1, true));
+                ins->functionReturnReg->value = m_builder.CreateICmpSGT(index, llvm::ConstantInt::get(m_builder.getInt64Ty(), -1, true));
                 break;
             }
 
@@ -951,8 +949,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 statement.body = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
 
                 // Use last reg
-                assert(step.args.size() == 1);
-                const auto &reg = step.args[0];
+                assert(ins->args.size() == 1);
+                const auto &reg = ins->args[0];
                 assert(reg.first == Compiler::StaticType::Bool);
                 statement.condition = m_utils.castValue(reg.second, reg.first);
 
@@ -1028,8 +1026,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 loop.afterLoop = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
 
                 // Use last reg for count
-                assert(step.args.size() == 1);
-                const auto &reg = step.args[0];
+                assert(ins->args.size() == 1);
+                const auto &reg = ins->args[0];
                 assert(reg.first == Compiler::StaticType::Number);
                 llvm::Value *count = m_utils.castValue(reg.second, reg.first);
                 llvm::Value *isInf = m_builder.CreateFCmpOEQ(count, llvm::ConstantFP::getInfinity(m_builder.getDoubleTy(), false));
@@ -1072,7 +1070,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 assert(!loops.empty());
                 LLVMLoop &loop = loops.back();
                 llvm::Value *index = m_builder.CreateLoad(m_builder.getInt64Ty(), loop.index);
-                step.functionReturnReg->value = m_builder.CreateUIToFP(index, m_builder.getDoubleTy());
+                ins->functionReturnReg->value = m_builder.CreateUIToFP(index, m_builder.getDoubleTy());
                 break;
             }
 
@@ -1085,8 +1083,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 loop.afterLoop = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
 
                 // Use last reg
-                assert(step.args.size() == 1);
-                const auto &reg = step.args[0];
+                assert(ins->args.size() == 1);
+                const auto &reg = ins->args[0];
                 assert(reg.first == Compiler::StaticType::Bool);
                 llvm::Value *condition = m_utils.castValue(reg.second, reg.first);
                 m_builder.CreateCondBr(condition, body, loop.afterLoop);
@@ -1106,8 +1104,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 loop.afterLoop = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
 
                 // Use last reg
-                assert(step.args.size() == 1);
-                const auto &reg = step.args[0];
+                assert(ins->args.size() == 1);
+                const auto &reg = ins->args[0];
                 assert(reg.first == Compiler::StaticType::Bool);
                 llvm::Value *condition = m_utils.castValue(reg.second, reg.first);
                 m_builder.CreateCondBr(condition, loop.afterLoop, body);
@@ -1160,13 +1158,13 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
             }
 
             case LLVMInstruction::Type::CallProcedure: {
-                assert(step.procedurePrototype);
-                assert(step.args.size() == step.procedurePrototype->argumentTypes().size());
+                assert(ins->procedurePrototype);
+                assert(ins->args.size() == ins->procedurePrototype->argumentTypes().size());
                 m_utils.freeScopeHeap();
                 m_utils.syncVariables(targetVariables);
 
-                std::string name = getMainFunctionName(step.procedurePrototype);
-                llvm::FunctionType *type = getMainFunctionType(step.procedurePrototype);
+                std::string name = getMainFunctionName(ins->procedurePrototype);
+                llvm::FunctionType *type = getMainFunctionType(ins->procedurePrototype);
                 std::vector<llvm::Value *> args;
 
                 for (size_t i = 0; i < m_defaultArgCount; i++)
@@ -1179,7 +1177,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                     args.push_back(m_procedurePrototype ? warpArg : m_builder.getInt1(false));
 
                 // Add procedure args
-                for (const auto &arg : step.args) {
+                for (const auto &arg : ins->args) {
                     if (arg.first == Compiler::StaticType::Unknown)
                         args.push_back(m_utils.createValue(arg.second));
                     else
@@ -1188,7 +1186,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
                 llvm::Value *handle = m_builder.CreateCall(m_utils.functions().resolveFunction(name, type), args);
 
-                if (!m_warp && !step.procedurePrototype->warp()) {
+                if (!m_warp && !ins->procedurePrototype->warp()) {
                     llvm::BasicBlock *suspendBranch = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
                     llvm::BasicBlock *nextBranch = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
                     m_builder.CreateCondBr(m_builder.CreateIsNull(handle), nextBranch, suspendBranch);
@@ -1207,8 +1205,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
             case LLVMInstruction::Type::ProcedureArg: {
                 assert(m_procedurePrototype);
-                llvm::Value *arg = m_function->getArg(m_defaultArgCount + 1 + step.procedureArgIndex); // omit warp arg
-                step.functionReturnReg->value = arg;
+                llvm::Value *arg = m_function->getArg(m_defaultArgCount + 1 + ins->procedureArgIndex); // omit warp arg
+                ins->functionReturnReg->value = arg;
                 break;
             }
         }

From 9850bed96ced40bae3ffb4095585eaa5e756be0d Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Mon, 4 Aug 2025 13:33:02 +0200
Subject: [PATCH 66/79] LLVMCodeBuilder: Switch to state machine approach

---
 src/engine/internal/llvm/llvmcodebuilder.cpp | 129 ++++++++++++++++++-
 1 file changed, 127 insertions(+), 2 deletions(-)

diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp
index 60d64f1e..b2f8de65 100644
--- a/src/engine/internal/llvm/llvmcodebuilder.cpp
+++ b/src/engine/internal/llvm/llvmcodebuilder.cpp
@@ -98,8 +98,10 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
     m_utils.init(m_function, targetVariables, targetLists);
 
-    // Execute recorded steps
-    for (LLVMInstruction *ins = m_instructions.first(); ins; ins = ins->next) {
+    // Execute recorded instructions
+    LLVMInstruction *ins = m_instructions.first();
+
+    while (ins) {
         switch (ins->type) {
             case LLVMInstruction::Type::FunctionCall: {
                 std::vector<llvm::Type *> types;
@@ -136,6 +138,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                         m_utils.freeStringLater(ins->functionReturnReg->value);
                 }
 
+                ins = ins->next;
                 break;
             }
 
@@ -146,6 +149,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Value *num1 = m_utils.removeNaN(m_utils.castValue(arg1.second, arg1.first));
                 llvm::Value *num2 = m_utils.removeNaN(m_utils.castValue(arg2.second, arg2.first));
                 ins->functionReturnReg->value = m_builder.CreateFAdd(num1, num2);
+
+                ins = ins->next;
                 break;
             }
 
@@ -156,6 +161,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Value *num1 = m_utils.removeNaN(m_utils.castValue(arg1.second, arg1.first));
                 llvm::Value *num2 = m_utils.removeNaN(m_utils.castValue(arg2.second, arg2.first));
                 ins->functionReturnReg->value = m_builder.CreateFSub(num1, num2);
+
+                ins = ins->next;
                 break;
             }
 
@@ -166,6 +173,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Value *num1 = m_utils.removeNaN(m_utils.castValue(arg1.second, arg1.first));
                 llvm::Value *num2 = m_utils.removeNaN(m_utils.castValue(arg2.second, arg2.first));
                 ins->functionReturnReg->value = m_builder.CreateFMul(num1, num2);
+
+                ins = ins->next;
                 break;
             }
 
@@ -176,6 +185,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Value *num1 = m_utils.removeNaN(m_utils.castValue(arg1.second, arg1.first));
                 llvm::Value *num2 = m_utils.removeNaN(m_utils.castValue(arg2.second, arg2.first));
                 ins->functionReturnReg->value = m_builder.CreateFDiv(num1, num2);
+
+                ins = ins->next;
                 break;
             }
 
@@ -210,6 +221,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                     }
                 }
 
+                ins = ins->next;
                 break;
             }
 
@@ -220,6 +232,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Value *from = m_builder.CreateFPToSI(m_utils.castValue(arg1.second, arg1.first), m_builder.getInt64Ty());
                 llvm::Value *to = m_builder.CreateFPToSI(m_utils.castValue(arg2.second, arg2.first), m_builder.getInt64Ty());
                 ins->functionReturnReg->value = m_builder.CreateCall(m_utils.functions().resolve_llvm_random_long(), { executionContextPtr, from, to });
+
+                ins = ins->next;
                 break;
             }
 
@@ -228,6 +242,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 const auto &arg1 = ins->args[0].second;
                 const auto &arg2 = ins->args[1].second;
                 ins->functionReturnReg->value = m_utils.createComparison(arg1, arg2, LLVMBuildUtils::Comparison::EQ);
+
+                ins = ins->next;
                 break;
             }
 
@@ -236,6 +252,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 const auto &arg1 = ins->args[0].second;
                 const auto &arg2 = ins->args[1].second;
                 ins->functionReturnReg->value = m_utils.createComparison(arg1, arg2, LLVMBuildUtils::Comparison::GT);
+
+                ins = ins->next;
                 break;
             }
 
@@ -244,6 +262,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 const auto &arg1 = ins->args[0].second;
                 const auto &arg2 = ins->args[1].second;
                 ins->functionReturnReg->value = m_utils.createComparison(arg1, arg2, LLVMBuildUtils::Comparison::LT);
+
+                ins = ins->next;
                 break;
             }
 
@@ -252,6 +272,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 const auto &arg1 = ins->args[0].second;
                 const auto &arg2 = ins->args[1].second;
                 ins->functionReturnReg->value = m_utils.createStringComparison(arg1, arg2, true);
+
+                ins = ins->next;
                 break;
             }
 
@@ -260,6 +282,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 const auto &arg1 = ins->args[0].second;
                 const auto &arg2 = ins->args[1].second;
                 ins->functionReturnReg->value = m_utils.createStringComparison(arg1, arg2, false);
+
+                ins = ins->next;
                 break;
             }
 
@@ -270,6 +294,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Value *bool1 = m_utils.castValue(arg1.second, arg1.first);
                 llvm::Value *bool2 = m_utils.castValue(arg2.second, arg2.first);
                 ins->functionReturnReg->value = m_builder.CreateAnd(bool1, bool2);
+
+                ins = ins->next;
                 break;
             }
 
@@ -280,6 +306,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Value *bool1 = m_utils.castValue(arg1.second, arg1.first);
                 llvm::Value *bool2 = m_utils.castValue(arg2.second, arg2.first);
                 ins->functionReturnReg->value = m_builder.CreateOr(bool1, bool2);
+
+                ins = ins->next;
                 break;
             }
 
@@ -288,6 +316,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 const auto &arg = ins->args[0];
                 llvm::Value *value = m_utils.castValue(arg.second, arg.first);
                 ins->functionReturnReg->value = m_builder.CreateNot(value);
+
+                ins = ins->next;
                 break;
             }
 
@@ -302,6 +332,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Value *value = m_builder.CreateFRem(num1, num2);                                // rem(a, b)
                 llvm::Value *cond = m_builder.CreateFCmpOLT(m_builder.CreateFDiv(value, num2), zero); // rem(a, b) / b < 0.0                                                            // rem(a, b)
                 ins->functionReturnReg->value = m_builder.CreateSelect(cond, m_builder.CreateFAdd(value, num2), value);
+
+                ins = ins->next;
                 break;
             }
 
@@ -319,6 +351,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Value *negativeCond = m_builder.CreateFCmpOGE(num, llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(-0.5)));                               // num >= -0.5
                 llvm::Value *negativeRound = m_builder.CreateCall(floorFunc, m_builder.CreateFAdd(num, llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.5)))); // floor(x + 0.5)
                 ins->functionReturnReg->value = m_builder.CreateSelect(notNegative, roundNum, m_builder.CreateSelect(negativeCond, negativeZero, negativeRound));
+
+                ins = ins->next;
                 break;
             }
 
@@ -328,6 +362,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Function *absFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::fabs, m_builder.getDoubleTy());
                 llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
                 ins->functionReturnReg->value = m_builder.CreateCall(absFunc, num);
+
+                ins = ins->next;
                 break;
             }
 
@@ -337,6 +373,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Function *floorFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::floor, m_builder.getDoubleTy());
                 llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
                 ins->functionReturnReg->value = m_builder.CreateCall(floorFunc, num);
+
+                ins = ins->next;
                 break;
             }
 
@@ -346,6 +384,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Function *ceilFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::ceil, m_builder.getDoubleTy());
                 llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
                 ins->functionReturnReg->value = m_builder.CreateCall(ceilFunc, num);
+
+                ins = ins->next;
                 break;
             }
 
@@ -358,6 +398,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Function *sqrtFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::sqrt, m_builder.getDoubleTy());
                 llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
                 ins->functionReturnReg->value = m_builder.CreateFAdd(m_builder.CreateCall(sqrtFunc, num), zero);
+
+                ins = ins->next;
                 break;
             }
 
@@ -376,6 +418,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Value *sinResult = m_builder.CreateCall(sinFunc, m_builder.CreateFDiv(m_builder.CreateFMul(num, pi), piDeg)); // sin(x * pi / 180)
                 llvm::Value *rounded = m_builder.CreateCall(roundFunc, m_builder.CreateFMul(sinResult, factor));                    // round(sin(x * 180) * 1e10)
                 ins->functionReturnReg->value = m_builder.CreateFAdd(m_builder.CreateFDiv(rounded, factor), zero);
+
+                ins = ins->next;
                 break;
             }
 
@@ -392,6 +436,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Value *cosResult = m_builder.CreateCall(cosFunc, m_builder.CreateFDiv(m_builder.CreateFMul(num, pi), piDeg)); // cos(x * pi / 180)
                 llvm::Value *rounded = m_builder.CreateCall(roundFunc, m_builder.CreateFMul(cosResult, factor));                    // round(cos(x * 180) * 1e10)
                 ins->functionReturnReg->value = m_builder.CreateFDiv(rounded, factor);
+
+                ins = ins->next;
                 break;
             }
 
@@ -424,6 +470,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Value *result = m_builder.CreateFAdd(m_builder.CreateFDiv(rounded, factor), zero);                            // round(tan(x * pi / 180.0) * 1e10) / 1e10 + 0.0
                 llvm::Value *inner = m_builder.CreateSelect(m_builder.CreateOr(isUndefined3, isUndefined4), negInf, result);
                 ins->functionReturnReg->value = m_builder.CreateSelect(m_builder.CreateOr(isUndefined1, isUndefined2), posInf, inner);
+
+                ins = ins->next;
                 break;
             }
 
@@ -438,6 +486,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Function *asinFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::asin, m_builder.getDoubleTy());
                 llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
                 ins->functionReturnReg->value = m_builder.CreateFAdd(m_builder.CreateFDiv(m_builder.CreateFMul(m_builder.CreateCall(asinFunc, num), piDeg), pi), zero);
+
+                ins = ins->next;
                 break;
             }
 
@@ -450,6 +500,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Function *acosFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::acos, m_builder.getDoubleTy());
                 llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
                 ins->functionReturnReg->value = m_builder.CreateFDiv(m_builder.CreateFMul(m_builder.CreateCall(acosFunc, num), piDeg), pi);
+
+                ins = ins->next;
                 break;
             }
 
@@ -462,6 +514,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Function *atanFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::atan, m_builder.getDoubleTy());
                 llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
                 ins->functionReturnReg->value = m_builder.CreateFDiv(m_builder.CreateFMul(m_builder.CreateCall(atanFunc, num), piDeg), pi);
+
+                ins = ins->next;
                 break;
             }
 
@@ -472,6 +526,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Function *logFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::log, m_builder.getDoubleTy());
                 llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
                 ins->functionReturnReg->value = m_builder.CreateCall(logFunc, num);
+
+                ins = ins->next;
                 break;
             }
 
@@ -482,6 +538,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Function *log10Func = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::log10, m_builder.getDoubleTy());
                 llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
                 ins->functionReturnReg->value = m_builder.CreateCall(log10Func, num);
+
+                ins = ins->next;
                 break;
             }
 
@@ -492,6 +550,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Function *expFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::exp, m_builder.getDoubleTy());
                 llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
                 ins->functionReturnReg->value = m_builder.CreateCall(expFunc, num);
+
+                ins = ins->next;
                 break;
             }
 
@@ -502,6 +562,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Function *expFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::exp10, m_builder.getDoubleTy());
                 llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
                 ins->functionReturnReg->value = m_builder.CreateCall(expFunc, num);
+
+                ins = ins->next;
                 break;
             }
 
@@ -545,6 +607,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 m_builder.CreateCall(memcpyFunc, { writePtr, data2, m_builder.CreateMul(m_builder.CreateAdd(size2, m_builder.getInt64(1)), m_builder.getInt64(2)), m_builder.getInt1(false) });
 
                 ins->functionReturnReg->value = result;
+
+                ins = ins->next;
                 break;
             }
 
@@ -584,6 +648,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 m_builder.CreateStore(m_builder.CreateSelect(inRange, m_builder.getInt64(1), m_builder.getInt64(0)), sizeField);
 
                 ins->functionReturnReg->value = result;
+
+                ins = ins->next;
                 break;
             }
 
@@ -594,6 +660,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Value *sizeField = m_builder.CreateStructGEP(m_stringPtrType, str, 1);
                 llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), sizeField);
                 ins->functionReturnReg->value = m_builder.CreateSIToFP(size, m_builder.getDoubleTy());
+
+                ins = ins->next;
                 break;
             }
 
@@ -616,6 +684,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 }
 
                 ins->functionReturnReg->value = m_builder.CreateSelect(cond, trueValue, falseValue);
+
+                ins = ins->next;
                 break;
             }
 
@@ -646,6 +716,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 }
 
                 ins->functionReturnReg->value = m_utils.addAlloca(type);
+
+                ins = ins->next;
                 break;
             }
 
@@ -655,6 +727,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 const auto &arg2 = ins->args[1];
                 llvm::Value *converted = m_utils.castValue(arg2.second, arg2.first);
                 m_builder.CreateStore(converted, arg1.second->value);
+
+                ins = ins->next;
                 break;
             }
 
@@ -678,6 +752,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 }
 
                 ins->functionReturnReg->value = m_builder.CreateLoad(type, arg.second->value);
+
+                ins = ins->next;
                 break;
             }
 
@@ -715,6 +791,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 }*/
 
                 m_utils.createValueStore(arg.second, varPtr.stackPtr, argType, varType);
+
+                ins = ins->next;
                 break;
             }
 
@@ -728,6 +806,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
                 ins->functionReturnReg->value = varPtr.onStack && !(ins->loopCondition && !m_warp) ? varPtr.stackPtr : varPtr.heapPtr;
                 ins->functionReturnReg->setType(type);
+
+                ins = ins->next;
                 break;
             }
 
@@ -735,6 +815,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 assert(ins->args.size() == 0);
                 LLVMListPtr &listPtr = m_utils.listPtr(ins->workList);
                 m_builder.CreateCall(m_utils.functions().resolve_list_clear(), listPtr.ptr);
+
+                ins = ins->next;
                 break;
             }
 
@@ -760,6 +842,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 m_builder.CreateBr(nextBlock);
 
                 m_builder.SetInsertPoint(nextBlock);
+
+                ins = ins->next;
                 break;
             }
 
@@ -798,6 +882,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
                 m_builder.SetInsertPoint(nextBlock);
 
+                ins = ins->next;
                 break;
             }
 
@@ -832,6 +917,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 m_builder.CreateBr(nextBlock);
 
                 m_builder.SetInsertPoint(nextBlock);
+
+                ins = ins->next;
                 break;
             }
 
@@ -865,6 +952,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 m_builder.CreateBr(nextBlock);
 
                 m_builder.SetInsertPoint(nextBlock);
+
+                ins = ins->next;
                 break;
             }
 
@@ -874,6 +963,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 llvm::Value *ptr = m_builder.CreateCall(m_utils.functions().resolve_list_to_string(), listPtr.ptr);
                 m_utils.freeStringLater(ptr);
                 ins->functionReturnReg->value = ptr;
+
+                ins = ins->next;
                 break;
             }
 
@@ -899,6 +990,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 index = m_builder.CreateFPToUI(index, m_builder.getInt64Ty());
                 ins->functionReturnReg->value = m_builder.CreateSelect(inRange, m_utils.getListItem(listPtr, index), null);
                 ins->functionReturnReg->setType(listType);
+
+                ins = ins->next;
                 break;
             }
 
@@ -907,6 +1000,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 const LLVMListPtr &listPtr = m_utils.listPtr(ins->workList);
                 llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.sizePtr);
                 ins->functionReturnReg->value = m_builder.CreateUIToFP(size, m_builder.getDoubleTy());
+
+                ins = ins->next;
                 break;
             }
 
@@ -921,6 +1016,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                     listType = m_typeAnalyzer.listType(ins->workList, ins, Compiler::StaticType::Unknown, false);
 
                 ins->functionReturnReg->value = m_builder.CreateSIToFP(m_utils.getListItemIndex(listPtr, listType, arg.second), m_builder.getDoubleTy());
+
+                ins = ins->next;
                 break;
             }
 
@@ -936,11 +1033,15 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
                 llvm::Value *index = m_utils.getListItemIndex(listPtr, listType, arg.second);
                 ins->functionReturnReg->value = m_builder.CreateICmpSGT(index, llvm::ConstantInt::get(m_builder.getInt64Ty(), -1, true));
+
+                ins = ins->next;
                 break;
             }
 
             case LLVMInstruction::Type::Yield:
                 createSuspend(coro.get(), warpArg, targetVariables);
+
+                ins = ins->next;
                 break;
 
             case LLVMInstruction::Type::BeginIf: {
@@ -959,6 +1060,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
                 ifStatements.push_back(statement);
                 m_utils.pushScopeLevel();
+
+                ins = ins->next;
                 break;
             }
 
@@ -982,6 +1085,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
                 // Switch to the else branch
                 m_builder.SetInsertPoint(statement.elseBranch);
+
+                ins = ins->next;
                 break;
             }
 
@@ -1008,6 +1113,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
                 ifStatements.pop_back();
                 m_utils.popScopeLevel();
+
+                ins = ins->next;
                 break;
             }
 
@@ -1063,6 +1170,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
                 loops.push_back(loop);
                 m_utils.pushScopeLevel();
+
+                ins = ins->next;
                 break;
             }
 
@@ -1071,6 +1180,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 LLVMLoop &loop = loops.back();
                 llvm::Value *index = m_builder.CreateLoad(m_builder.getInt64Ty(), loop.index);
                 ins->functionReturnReg->value = m_builder.CreateUIToFP(index, m_builder.getDoubleTy());
+
+                ins = ins->next;
                 break;
             }
 
@@ -1092,6 +1203,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 // Switch to body branch
                 m_builder.SetInsertPoint(body);
                 m_utils.pushScopeLevel();
+
+                ins = ins->next;
                 break;
             }
 
@@ -1113,6 +1226,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 // Switch to body branch
                 m_builder.SetInsertPoint(body);
                 m_utils.pushScopeLevel();
+
+                ins = ins->next;
                 break;
             }
 
@@ -1123,6 +1238,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 m_builder.CreateBr(loop.conditionBranch);
                 m_builder.SetInsertPoint(loop.conditionBranch);
                 loops.push_back(loop);
+
+                ins = ins->next;
                 break;
             }
 
@@ -1146,6 +1263,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
 
                 loops.pop_back();
                 m_utils.popScopeLevel();
+
+                ins = ins->next;
                 break;
             }
 
@@ -1154,6 +1273,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 m_builder.CreateBr(endBranch);
                 llvm::BasicBlock *nextBranch = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
                 m_builder.SetInsertPoint(nextBranch);
+
+                ins = ins->next;
                 break;
             }
 
@@ -1200,6 +1321,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 }
 
                 m_utils.reloadVariables(targetVariables);
+
+                ins = ins->next;
                 break;
             }
 
@@ -1207,6 +1330,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 assert(m_procedurePrototype);
                 llvm::Value *arg = m_function->getArg(m_defaultArgCount + 1 + ins->procedureArgIndex); // omit warp arg
                 ins->functionReturnReg->value = arg;
+
+                ins = ins->next;
                 break;
             }
         }

From 56951766cb7f30f8bee7a159ead46ba87a7f3ec3 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Mon, 4 Aug 2025 14:09:39 +0200
Subject: [PATCH 67/79] LLVMBuildUtils: Add builder getter

---
 src/engine/internal/llvm/llvmbuildutils.cpp | 5 +++++
 src/engine/internal/llvm/llvmbuildutils.h   | 1 +
 2 files changed, 6 insertions(+)

diff --git a/src/engine/internal/llvm/llvmbuildutils.cpp b/src/engine/internal/llvm/llvmbuildutils.cpp
index 472b6b19..068fd061 100644
--- a/src/engine/internal/llvm/llvmbuildutils.cpp
+++ b/src/engine/internal/llvm/llvmbuildutils.cpp
@@ -83,6 +83,11 @@ void LLVMBuildUtils::end()
     freeScopeHeap();
 }
 
+llvm::IRBuilder<> &LLVMBuildUtils::builder()
+{
+    return m_builder;
+}
+
 LLVMFunctions &LLVMBuildUtils::functions()
 {
     return m_functions;
diff --git a/src/engine/internal/llvm/llvmbuildutils.h b/src/engine/internal/llvm/llvmbuildutils.h
index 0a3d3f9b..5f6b83ee 100644
--- a/src/engine/internal/llvm/llvmbuildutils.h
+++ b/src/engine/internal/llvm/llvmbuildutils.h
@@ -28,6 +28,7 @@ class LLVMBuildUtils
         void init(llvm::Function *function, llvm::Value *targetVariables, llvm::Value *targetLists);
         void end();
 
+        llvm::IRBuilder<> &builder();
         LLVMFunctions &functions();
 
         void createVariablePtr(Variable *variable);

From d2256f84cd61e49c4d890a19800ce7a46a522caf Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Mon, 4 Aug 2025 14:41:03 +0200
Subject: [PATCH 68/79] Add a separate class for building LLVM instructions

---
 src/engine/internal/llvm/CMakeLists.txt       |  2 ++
 .../internal/llvm/instructions/CMakeLists.txt |  8 +++++
 .../llvm/instructions/instructionbuilder.cpp  | 25 ++++++++++++++++
 .../llvm/instructions/instructionbuilder.h    | 21 +++++++++++++
 .../llvm/instructions/instructiongroup.cpp    | 12 ++++++++
 .../llvm/instructions/instructiongroup.h      | 30 +++++++++++++++++++
 .../llvm/instructions/processresult.h         | 27 +++++++++++++++++
 7 files changed, 125 insertions(+)
 create mode 100644 src/engine/internal/llvm/instructions/CMakeLists.txt
 create mode 100644 src/engine/internal/llvm/instructions/instructionbuilder.cpp
 create mode 100644 src/engine/internal/llvm/instructions/instructionbuilder.h
 create mode 100644 src/engine/internal/llvm/instructions/instructiongroup.cpp
 create mode 100644 src/engine/internal/llvm/instructions/instructiongroup.h
 create mode 100644 src/engine/internal/llvm/instructions/processresult.h

diff --git a/src/engine/internal/llvm/CMakeLists.txt b/src/engine/internal/llvm/CMakeLists.txt
index b5d79d2a..629d1a28 100644
--- a/src/engine/internal/llvm/CMakeLists.txt
+++ b/src/engine/internal/llvm/CMakeLists.txt
@@ -28,3 +28,5 @@ target_sources(scratchcpp
     llvmexecutioncontext.cpp
     llvmexecutioncontext.h
 )
+
+add_subdirectory(instructions)
diff --git a/src/engine/internal/llvm/instructions/CMakeLists.txt b/src/engine/internal/llvm/instructions/CMakeLists.txt
new file mode 100644
index 00000000..e32f493b
--- /dev/null
+++ b/src/engine/internal/llvm/instructions/CMakeLists.txt
@@ -0,0 +1,8 @@
+target_sources(scratchcpp
+  PRIVATE
+    instructionbuilder.cpp
+    instructionbuilder.h
+    instructiongroup.cpp
+    instructiongroup.h
+    processresult.h
+)
diff --git a/src/engine/internal/llvm/instructions/instructionbuilder.cpp b/src/engine/internal/llvm/instructions/instructionbuilder.cpp
new file mode 100644
index 00000000..62fd942c
--- /dev/null
+++ b/src/engine/internal/llvm/instructions/instructionbuilder.cpp
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#include "instructionbuilder.h"
+
+using namespace libscratchcpp;
+using namespace libscratchcpp::llvmins;
+
+InstructionBuilder::InstructionBuilder(LLVMBuildUtils &utils)
+{
+    // Create groups
+}
+
+LLVMInstruction *InstructionBuilder::process(LLVMInstruction *ins)
+{
+    // Process all groups
+    for (const auto &group : m_groups) {
+        ProcessResult result = group->process(ins);
+
+        if (result.match)
+            return result.next;
+    }
+
+    assert(false); // instruction not found
+    return ins;
+}
diff --git a/src/engine/internal/llvm/instructions/instructionbuilder.h b/src/engine/internal/llvm/instructions/instructionbuilder.h
new file mode 100644
index 00000000..4c1190ae
--- /dev/null
+++ b/src/engine/internal/llvm/instructions/instructionbuilder.h
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "instructiongroup.h"
+
+namespace libscratchcpp::llvmins
+{
+
+class InstructionBuilder
+{
+    public:
+        InstructionBuilder(LLVMBuildUtils &utils);
+
+        LLVMInstruction *process(LLVMInstruction *ins);
+
+    private:
+        std::vector<std::shared_ptr<InstructionGroup>> m_groups;
+};
+
+} // namespace libscratchcpp::llvmins
diff --git a/src/engine/internal/llvm/instructions/instructiongroup.cpp b/src/engine/internal/llvm/instructions/instructiongroup.cpp
new file mode 100644
index 00000000..acc00ba8
--- /dev/null
+++ b/src/engine/internal/llvm/instructions/instructiongroup.cpp
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#include "instructiongroup.h"
+#include "../llvmbuildutils.h"
+
+using namespace libscratchcpp::llvmins;
+
+InstructionGroup::InstructionGroup(LLVMBuildUtils &utils) :
+    m_utils(utils),
+    m_builder(utils.builder())
+{
+}
diff --git a/src/engine/internal/llvm/instructions/instructiongroup.h b/src/engine/internal/llvm/instructions/instructiongroup.h
new file mode 100644
index 00000000..6017f2ab
--- /dev/null
+++ b/src/engine/internal/llvm/instructions/instructiongroup.h
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include <llvm/IR/IRBuilder.h>
+
+#include "processresult.h"
+
+namespace libscratchcpp
+{
+
+class LLVMBuildUtils;
+
+namespace llvmins
+{
+
+class InstructionGroup
+{
+    public:
+        InstructionGroup(LLVMBuildUtils &utils);
+
+        virtual ProcessResult process(LLVMInstruction *ins) = 0;
+
+    protected:
+        LLVMBuildUtils &m_utils;
+        llvm::IRBuilder<> &m_builder;
+};
+
+} // namespace llvmins
+} // namespace libscratchcpp
diff --git a/src/engine/internal/llvm/instructions/processresult.h b/src/engine/internal/llvm/instructions/processresult.h
new file mode 100644
index 00000000..0846c2be
--- /dev/null
+++ b/src/engine/internal/llvm/instructions/processresult.h
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+namespace libscratchcpp
+{
+
+class LLVMInstruction;
+
+namespace llvmins
+{
+
+// Result of group processing
+struct ProcessResult
+{
+        ProcessResult(bool match, LLVMInstruction *next) :
+            match(match),
+            next(next)
+        {
+        }
+
+        bool match = false;              // whether the desired instruction was found
+        LLVMInstruction *next = nullptr; // next instruction (state)
+};
+
+} // namespace llvmins
+} // namespace libscratchcpp

From 97765690a84747bd1032ea59911582ed65c0f764 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Mon, 4 Aug 2025 19:38:24 +0200
Subject: [PATCH 69/79] Add empty LLVM instruction groups

---
 .../internal/llvm/instructions/CMakeLists.txt | 22 +++++++++++++++++++
 .../internal/llvm/instructions/comparison.cpp | 10 +++++++++
 .../internal/llvm/instructions/comparison.h   | 18 +++++++++++++++
 .../internal/llvm/instructions/control.cpp    | 10 +++++++++
 .../internal/llvm/instructions/control.h      | 18 +++++++++++++++
 .../internal/llvm/instructions/functions.cpp  | 10 +++++++++
 .../internal/llvm/instructions/functions.h    | 18 +++++++++++++++
 .../llvm/instructions/instructionbuilder.cpp  | 18 +++++++++++++++
 .../internal/llvm/instructions/lists.cpp      | 10 +++++++++
 src/engine/internal/llvm/instructions/lists.h | 18 +++++++++++++++
 .../internal/llvm/instructions/logic.cpp      | 10 +++++++++
 src/engine/internal/llvm/instructions/logic.h | 18 +++++++++++++++
 .../internal/llvm/instructions/math.cpp       | 10 +++++++++
 src/engine/internal/llvm/instructions/math.h  | 18 +++++++++++++++
 .../internal/llvm/instructions/procedures.cpp | 10 +++++++++
 .../internal/llvm/instructions/procedures.h   | 18 +++++++++++++++
 .../internal/llvm/instructions/string.cpp     | 10 +++++++++
 .../internal/llvm/instructions/string.h       | 18 +++++++++++++++
 .../internal/llvm/instructions/variables.cpp  | 10 +++++++++
 .../internal/llvm/instructions/variables.h    | 18 +++++++++++++++
 20 files changed, 292 insertions(+)
 create mode 100644 src/engine/internal/llvm/instructions/comparison.cpp
 create mode 100644 src/engine/internal/llvm/instructions/comparison.h
 create mode 100644 src/engine/internal/llvm/instructions/control.cpp
 create mode 100644 src/engine/internal/llvm/instructions/control.h
 create mode 100644 src/engine/internal/llvm/instructions/functions.cpp
 create mode 100644 src/engine/internal/llvm/instructions/functions.h
 create mode 100644 src/engine/internal/llvm/instructions/lists.cpp
 create mode 100644 src/engine/internal/llvm/instructions/lists.h
 create mode 100644 src/engine/internal/llvm/instructions/logic.cpp
 create mode 100644 src/engine/internal/llvm/instructions/logic.h
 create mode 100644 src/engine/internal/llvm/instructions/math.cpp
 create mode 100644 src/engine/internal/llvm/instructions/math.h
 create mode 100644 src/engine/internal/llvm/instructions/procedures.cpp
 create mode 100644 src/engine/internal/llvm/instructions/procedures.h
 create mode 100644 src/engine/internal/llvm/instructions/string.cpp
 create mode 100644 src/engine/internal/llvm/instructions/string.h
 create mode 100644 src/engine/internal/llvm/instructions/variables.cpp
 create mode 100644 src/engine/internal/llvm/instructions/variables.h

diff --git a/src/engine/internal/llvm/instructions/CMakeLists.txt b/src/engine/internal/llvm/instructions/CMakeLists.txt
index e32f493b..bdf67e3a 100644
--- a/src/engine/internal/llvm/instructions/CMakeLists.txt
+++ b/src/engine/internal/llvm/instructions/CMakeLists.txt
@@ -6,3 +6,25 @@ target_sources(scratchcpp
     instructiongroup.h
     processresult.h
 )
+
+target_sources(scratchcpp
+  PRIVATE
+    functions.cpp
+    functions.h
+    math.cpp
+    math.h
+    comparison.cpp
+    comparison.h
+    string.cpp
+    string.h
+    logic.cpp
+    logic.h
+    control.cpp
+    control.h
+    variables.cpp
+    variables.h
+    lists.cpp
+    lists.h
+    procedures.cpp
+    procedures.h
+)
diff --git a/src/engine/internal/llvm/instructions/comparison.cpp b/src/engine/internal/llvm/instructions/comparison.cpp
new file mode 100644
index 00000000..466d36db
--- /dev/null
+++ b/src/engine/internal/llvm/instructions/comparison.cpp
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#include "comparison.h"
+#include "../llvmbuildutils.h"
+
+using namespace libscratchcpp::llvmins;
+
+ProcessResult Comparison::process(LLVMInstruction *ins)
+{
+}
diff --git a/src/engine/internal/llvm/instructions/comparison.h b/src/engine/internal/llvm/instructions/comparison.h
new file mode 100644
index 00000000..c1774c1d
--- /dev/null
+++ b/src/engine/internal/llvm/instructions/comparison.h
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "instructiongroup.h"
+
+namespace libscratchcpp::llvmins
+{
+
+class Comparison : public InstructionGroup
+{
+    public:
+        using InstructionGroup::InstructionGroup;
+
+        ProcessResult process(LLVMInstruction *ins) override;
+};
+
+} // namespace libscratchcpp::llvmins
diff --git a/src/engine/internal/llvm/instructions/control.cpp b/src/engine/internal/llvm/instructions/control.cpp
new file mode 100644
index 00000000..804212a9
--- /dev/null
+++ b/src/engine/internal/llvm/instructions/control.cpp
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#include "control.h"
+#include "../llvmbuildutils.h"
+
+using namespace libscratchcpp::llvmins;
+
+ProcessResult Control::process(LLVMInstruction *ins)
+{
+}
diff --git a/src/engine/internal/llvm/instructions/control.h b/src/engine/internal/llvm/instructions/control.h
new file mode 100644
index 00000000..0769939c
--- /dev/null
+++ b/src/engine/internal/llvm/instructions/control.h
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "instructiongroup.h"
+
+namespace libscratchcpp::llvmins
+{
+
+class Control : public InstructionGroup
+{
+    public:
+        using InstructionGroup::InstructionGroup;
+
+        ProcessResult process(LLVMInstruction *ins) override;
+};
+
+} // namespace libscratchcpp::llvmins
diff --git a/src/engine/internal/llvm/instructions/functions.cpp b/src/engine/internal/llvm/instructions/functions.cpp
new file mode 100644
index 00000000..ee9e830b
--- /dev/null
+++ b/src/engine/internal/llvm/instructions/functions.cpp
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#include "functions.h"
+#include "../llvmbuildutils.h"
+
+using namespace libscratchcpp::llvmins;
+
+ProcessResult Functions::process(LLVMInstruction *ins)
+{
+}
diff --git a/src/engine/internal/llvm/instructions/functions.h b/src/engine/internal/llvm/instructions/functions.h
new file mode 100644
index 00000000..6c18d2ad
--- /dev/null
+++ b/src/engine/internal/llvm/instructions/functions.h
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "instructiongroup.h"
+
+namespace libscratchcpp::llvmins
+{
+
+class Functions : public InstructionGroup
+{
+    public:
+        using InstructionGroup::InstructionGroup;
+
+        ProcessResult process(LLVMInstruction *ins) override;
+};
+
+} // namespace libscratchcpp::llvmins
diff --git a/src/engine/internal/llvm/instructions/instructionbuilder.cpp b/src/engine/internal/llvm/instructions/instructionbuilder.cpp
index 62fd942c..2263f521 100644
--- a/src/engine/internal/llvm/instructions/instructionbuilder.cpp
+++ b/src/engine/internal/llvm/instructions/instructionbuilder.cpp
@@ -1,6 +1,15 @@
 // SPDX-License-Identifier: Apache-2.0
 
 #include "instructionbuilder.h"
+#include "functions.h"
+#include "math.h"
+#include "comparison.h"
+#include "string.h"
+#include "logic.h"
+#include "control.h"
+#include "variables.h"
+#include "lists.h"
+#include "procedures.h"
 
 using namespace libscratchcpp;
 using namespace libscratchcpp::llvmins;
@@ -8,6 +17,15 @@ using namespace libscratchcpp::llvmins;
 InstructionBuilder::InstructionBuilder(LLVMBuildUtils &utils)
 {
     // Create groups
+    m_groups.push_back(std::make_shared<Functions>(utils));
+    m_groups.push_back(std::make_shared<Math>(utils));
+    m_groups.push_back(std::make_shared<Comparison>(utils));
+    m_groups.push_back(std::make_shared<String>(utils));
+    m_groups.push_back(std::make_shared<Logic>(utils));
+    m_groups.push_back(std::make_shared<Control>(utils));
+    m_groups.push_back(std::make_shared<Variables>(utils));
+    m_groups.push_back(std::make_shared<Lists>(utils));
+    m_groups.push_back(std::make_shared<Procedures>(utils));
 }
 
 LLVMInstruction *InstructionBuilder::process(LLVMInstruction *ins)
diff --git a/src/engine/internal/llvm/instructions/lists.cpp b/src/engine/internal/llvm/instructions/lists.cpp
new file mode 100644
index 00000000..774d7c7c
--- /dev/null
+++ b/src/engine/internal/llvm/instructions/lists.cpp
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#include "lists.h"
+#include "../llvmbuildutils.h"
+
+using namespace libscratchcpp::llvmins;
+
+ProcessResult Lists::process(LLVMInstruction *ins)
+{
+}
diff --git a/src/engine/internal/llvm/instructions/lists.h b/src/engine/internal/llvm/instructions/lists.h
new file mode 100644
index 00000000..31b4b9cc
--- /dev/null
+++ b/src/engine/internal/llvm/instructions/lists.h
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "instructiongroup.h"
+
+namespace libscratchcpp::llvmins
+{
+
+class Lists : public InstructionGroup
+{
+    public:
+        using InstructionGroup::InstructionGroup;
+
+        ProcessResult process(LLVMInstruction *ins) override;
+};
+
+} // namespace libscratchcpp::llvmins
diff --git a/src/engine/internal/llvm/instructions/logic.cpp b/src/engine/internal/llvm/instructions/logic.cpp
new file mode 100644
index 00000000..68e73da0
--- /dev/null
+++ b/src/engine/internal/llvm/instructions/logic.cpp
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#include "logic.h"
+#include "../llvmbuildutils.h"
+
+using namespace libscratchcpp::llvmins;
+
+ProcessResult Logic::process(LLVMInstruction *ins)
+{
+}
diff --git a/src/engine/internal/llvm/instructions/logic.h b/src/engine/internal/llvm/instructions/logic.h
new file mode 100644
index 00000000..0df01551
--- /dev/null
+++ b/src/engine/internal/llvm/instructions/logic.h
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "instructiongroup.h"
+
+namespace libscratchcpp::llvmins
+{
+
+class Logic : public InstructionGroup
+{
+    public:
+        using InstructionGroup::InstructionGroup;
+
+        ProcessResult process(LLVMInstruction *ins) override;
+};
+
+} // namespace libscratchcpp::llvmins
diff --git a/src/engine/internal/llvm/instructions/math.cpp b/src/engine/internal/llvm/instructions/math.cpp
new file mode 100644
index 00000000..78312657
--- /dev/null
+++ b/src/engine/internal/llvm/instructions/math.cpp
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#include "math.h"
+#include "../llvmbuildutils.h"
+
+using namespace libscratchcpp::llvmins;
+
+ProcessResult Math::process(LLVMInstruction *ins)
+{
+}
diff --git a/src/engine/internal/llvm/instructions/math.h b/src/engine/internal/llvm/instructions/math.h
new file mode 100644
index 00000000..a3bb36a5
--- /dev/null
+++ b/src/engine/internal/llvm/instructions/math.h
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "instructiongroup.h"
+
+namespace libscratchcpp::llvmins
+{
+
+class Math : public InstructionGroup
+{
+    public:
+        using InstructionGroup::InstructionGroup;
+
+        ProcessResult process(LLVMInstruction *ins) override;
+};
+
+} // namespace libscratchcpp::llvmins
diff --git a/src/engine/internal/llvm/instructions/procedures.cpp b/src/engine/internal/llvm/instructions/procedures.cpp
new file mode 100644
index 00000000..23fd3eb7
--- /dev/null
+++ b/src/engine/internal/llvm/instructions/procedures.cpp
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#include "procedures.h"
+#include "../llvmbuildutils.h"
+
+using namespace libscratchcpp::llvmins;
+
+ProcessResult Procedures::process(LLVMInstruction *ins)
+{
+}
diff --git a/src/engine/internal/llvm/instructions/procedures.h b/src/engine/internal/llvm/instructions/procedures.h
new file mode 100644
index 00000000..f677bff7
--- /dev/null
+++ b/src/engine/internal/llvm/instructions/procedures.h
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "instructiongroup.h"
+
+namespace libscratchcpp::llvmins
+{
+
+class Procedures : public InstructionGroup
+{
+    public:
+        using InstructionGroup::InstructionGroup;
+
+        ProcessResult process(LLVMInstruction *ins) override;
+};
+
+} // namespace libscratchcpp::llvmins
diff --git a/src/engine/internal/llvm/instructions/string.cpp b/src/engine/internal/llvm/instructions/string.cpp
new file mode 100644
index 00000000..93b19610
--- /dev/null
+++ b/src/engine/internal/llvm/instructions/string.cpp
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#include "string.h"
+#include "../llvmbuildutils.h"
+
+using namespace libscratchcpp::llvmins;
+
+ProcessResult String::process(LLVMInstruction *ins)
+{
+}
diff --git a/src/engine/internal/llvm/instructions/string.h b/src/engine/internal/llvm/instructions/string.h
new file mode 100644
index 00000000..892d8287
--- /dev/null
+++ b/src/engine/internal/llvm/instructions/string.h
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "instructiongroup.h"
+
+namespace libscratchcpp::llvmins
+{
+
+class String : public InstructionGroup
+{
+    public:
+        using InstructionGroup::InstructionGroup;
+
+        ProcessResult process(LLVMInstruction *ins) override;
+};
+
+} // namespace libscratchcpp::llvmins
diff --git a/src/engine/internal/llvm/instructions/variables.cpp b/src/engine/internal/llvm/instructions/variables.cpp
new file mode 100644
index 00000000..94559cad
--- /dev/null
+++ b/src/engine/internal/llvm/instructions/variables.cpp
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#include "variables.h"
+#include "../llvmbuildutils.h"
+
+using namespace libscratchcpp::llvmins;
+
+ProcessResult Variables::process(LLVMInstruction *ins)
+{
+}
diff --git a/src/engine/internal/llvm/instructions/variables.h b/src/engine/internal/llvm/instructions/variables.h
new file mode 100644
index 00000000..26f5110c
--- /dev/null
+++ b/src/engine/internal/llvm/instructions/variables.h
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "instructiongroup.h"
+
+namespace libscratchcpp::llvmins
+{
+
+class Variables : public InstructionGroup
+{
+    public:
+        using InstructionGroup::InstructionGroup;
+
+        ProcessResult process(LLVMInstruction *ins) override;
+};
+
+} // namespace libscratchcpp::llvmins

From 30bfcc87f4f5edc54d20ab7299f51fd3b7bd5dd9 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Mon, 4 Aug 2025 19:46:40 +0200
Subject: [PATCH 70/79] LLVMBuildUtils: Add getters for target variables and
 lists

---
 src/engine/internal/llvm/llvmbuildutils.cpp | 12 ++++++++++++
 src/engine/internal/llvm/llvmbuildutils.h   |  5 +++++
 2 files changed, 17 insertions(+)

diff --git a/src/engine/internal/llvm/llvmbuildutils.cpp b/src/engine/internal/llvm/llvmbuildutils.cpp
index 068fd061..1ba517fe 100644
--- a/src/engine/internal/llvm/llvmbuildutils.cpp
+++ b/src/engine/internal/llvm/llvmbuildutils.cpp
@@ -33,6 +33,8 @@ LLVMBuildUtils::LLVMBuildUtils(LLVMCompilerContext *ctx, llvm::IRBuilder<> &buil
 void LLVMBuildUtils::init(llvm::Function *function, llvm::Value *targetVariables, llvm::Value *targetLists)
 {
     m_function = function;
+    m_targetVariables = targetVariables;
+    m_targetLists = targetLists;
     m_stringHeap.clear();
     pushScopeLevel();
 
@@ -93,6 +95,16 @@ LLVMFunctions &LLVMBuildUtils::functions()
     return m_functions;
 }
 
+llvm::Value *LLVMBuildUtils::targetVariables()
+{
+    return m_targetVariables;
+}
+
+llvm::Value *LLVMBuildUtils::targetLists()
+{
+    return m_targetLists;
+}
+
 void LLVMBuildUtils::createVariablePtr(Variable *variable)
 {
     if (m_variablePtrs.find(variable) == m_variablePtrs.cend())
diff --git a/src/engine/internal/llvm/llvmbuildutils.h b/src/engine/internal/llvm/llvmbuildutils.h
index 5f6b83ee..72bbe3d6 100644
--- a/src/engine/internal/llvm/llvmbuildutils.h
+++ b/src/engine/internal/llvm/llvmbuildutils.h
@@ -31,6 +31,9 @@ class LLVMBuildUtils
         llvm::IRBuilder<> &builder();
         LLVMFunctions &functions();
 
+        llvm::Value *targetVariables();
+        llvm::Value *targetLists();
+
         void createVariablePtr(Variable *variable);
         void createListPtr(List *list);
 
@@ -90,9 +93,11 @@ class LLVMBuildUtils
         llvm::StructType *m_valueDataType = nullptr;
         llvm::StructType *m_stringPtrType = nullptr;
 
+        llvm::Value *m_targetVariables = nullptr;
         std::unordered_map<Variable *, size_t> m_targetVariableMap;
         std::unordered_map<Variable *, LLVMVariablePtr> m_variablePtrs;
 
+        llvm::Value *m_targetLists = nullptr;
         std::unordered_map<List *, size_t> m_targetListMap;
         std::unordered_map<List *, LLVMListPtr> m_listPtrs;
 

From b1a141d6685c7a840e3f5bfab877b7811bd24a2b Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Mon, 4 Aug 2025 20:06:02 +0200
Subject: [PATCH 71/79] Store LLVM script function arguments in LLVMBuildUtils

---
 src/engine/internal/llvm/llvmbuildutils.cpp  | 49 ++++++++++++++++++--
 src/engine/internal/llvm/llvmbuildutils.h    | 18 ++++++-
 src/engine/internal/llvm/llvmcodebuilder.cpp | 40 ++++++----------
 3 files changed, 74 insertions(+), 33 deletions(-)

diff --git a/src/engine/internal/llvm/llvmbuildutils.cpp b/src/engine/internal/llvm/llvmbuildutils.cpp
index 1ba517fe..c5bc14e9 100644
--- a/src/engine/internal/llvm/llvmbuildutils.cpp
+++ b/src/engine/internal/llvm/llvmbuildutils.cpp
@@ -30,17 +30,26 @@ LLVMBuildUtils::LLVMBuildUtils(LLVMCompilerContext *ctx, llvm::IRBuilder<> &buil
     createListMap();
 }
 
-void LLVMBuildUtils::init(llvm::Function *function, llvm::Value *targetVariables, llvm::Value *targetLists)
+void LLVMBuildUtils::init(llvm::Function *function, BlockPrototype *procedurePrototype, bool warp)
 {
     m_function = function;
-    m_targetVariables = targetVariables;
-    m_targetLists = targetLists;
+    m_procedurePrototype = procedurePrototype;
+
+    m_executionContextPtr = m_function->getArg(0);
+    m_targetPtr = m_function->getArg(1);
+    m_targetVariables = m_function->getArg(2);
+    m_targetLists = m_function->getArg(3);
+    m_warpArg = m_procedurePrototype ? m_function->getArg(4) : nullptr;
+
+    if (m_procedurePrototype && m_warp)
+        m_function->addFnAttr(llvm::Attribute::InlineHint);
+
     m_stringHeap.clear();
     pushScopeLevel();
 
     // Create variable pointers
     for (auto &[var, varPtr] : m_variablePtrs) {
-        llvm::Value *ptr = getVariablePtr(targetVariables, var);
+        llvm::Value *ptr = getVariablePtr(m_targetVariables, var);
 
         // Direct access
         varPtr.heapPtr = ptr;
@@ -69,7 +78,7 @@ void LLVMBuildUtils::init(llvm::Function *function, llvm::Value *targetVariables
 
     // Create list pointers
     for (auto &[list, listPtr] : m_listPtrs) {
-        listPtr.ptr = getListPtr(targetLists, list);
+        listPtr.ptr = getListPtr(m_targetLists, list);
 
         listPtr.dataPtr = m_builder.CreateAlloca(m_valueDataType->getPointerTo()->getPointerTo());
         m_builder.CreateStore(m_builder.CreateCall(m_functions.resolve_list_data_ptr(), listPtr.ptr), listPtr.dataPtr);
@@ -85,6 +94,11 @@ void LLVMBuildUtils::end()
     freeScopeHeap();
 }
 
+llvm::LLVMContext &LLVMBuildUtils::llvmCtx()
+{
+    return m_llvmCtx;
+}
+
 llvm::IRBuilder<> &LLVMBuildUtils::builder()
 {
     return m_builder;
@@ -95,6 +109,26 @@ LLVMFunctions &LLVMBuildUtils::functions()
     return m_functions;
 }
 
+BlockPrototype *LLVMBuildUtils::procedurePrototype() const
+{
+    return m_procedurePrototype;
+}
+
+bool LLVMBuildUtils::warp() const
+{
+    return m_warp;
+}
+
+llvm::Value *LLVMBuildUtils::executionContextPtr()
+{
+    return m_executionContextPtr;
+}
+
+llvm::Value *LLVMBuildUtils::targetPtr()
+{
+    return m_targetPtr;
+}
+
 llvm::Value *LLVMBuildUtils::targetVariables()
 {
     return m_targetVariables;
@@ -105,6 +139,11 @@ llvm::Value *LLVMBuildUtils::targetLists()
     return m_targetLists;
 }
 
+llvm::Value *LLVMBuildUtils::warpArg()
+{
+    return m_warpArg;
+}
+
 void LLVMBuildUtils::createVariablePtr(Variable *variable)
 {
     if (m_variablePtrs.find(variable) == m_variablePtrs.cend())
diff --git a/src/engine/internal/llvm/llvmbuildutils.h b/src/engine/internal/llvm/llvmbuildutils.h
index 72bbe3d6..e36dbb8b 100644
--- a/src/engine/internal/llvm/llvmbuildutils.h
+++ b/src/engine/internal/llvm/llvmbuildutils.h
@@ -25,14 +25,21 @@ class LLVMBuildUtils
 
         LLVMBuildUtils(LLVMCompilerContext *ctx, llvm::IRBuilder<> &builder);
 
-        void init(llvm::Function *function, llvm::Value *targetVariables, llvm::Value *targetLists);
+        void init(llvm::Function *function, BlockPrototype *procedurePrototype, bool warp);
         void end();
 
+        llvm::LLVMContext &llvmCtx();
         llvm::IRBuilder<> &builder();
         LLVMFunctions &functions();
 
+        BlockPrototype *procedurePrototype() const;
+        bool warp() const;
+
+        llvm::Value *executionContextPtr();
+        llvm::Value *targetPtr();
         llvm::Value *targetVariables();
         llvm::Value *targetLists();
+        llvm::Value *warpArg();
 
         void createVariablePtr(Variable *variable);
         void createListPtr(List *list);
@@ -93,11 +100,18 @@ class LLVMBuildUtils
         llvm::StructType *m_valueDataType = nullptr;
         llvm::StructType *m_stringPtrType = nullptr;
 
+        BlockPrototype *m_procedurePrototype = nullptr;
+        bool m_warp = false;
+
+        llvm::Value *m_executionContextPtr = nullptr;
+        llvm::Value *m_targetPtr = nullptr;
         llvm::Value *m_targetVariables = nullptr;
+        llvm::Value *m_targetLists = nullptr;
+        llvm::Value *m_warpArg = nullptr;
+
         std::unordered_map<Variable *, size_t> m_targetVariableMap;
         std::unordered_map<Variable *, LLVMVariablePtr> m_variablePtrs;
 
-        llvm::Value *m_targetLists = nullptr;
         std::unordered_map<List *, size_t> m_targetListMap;
         std::unordered_map<List *, LLVMListPtr> m_listPtrs;
 
diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp
index b2f8de65..6cdd2d62 100644
--- a/src/engine/internal/llvm/llvmcodebuilder.cpp
+++ b/src/engine/internal/llvm/llvmcodebuilder.cpp
@@ -71,18 +71,6 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
     else
         m_function = llvm::Function::Create(funcType, llvm::Function::ExternalLinkage, funcName, m_module);
 
-    llvm::Value *executionContextPtr = m_function->getArg(0);
-    llvm::Value *targetPtr = m_function->getArg(1);
-    llvm::Value *targetVariables = m_function->getArg(2);
-    llvm::Value *targetLists = m_function->getArg(3);
-    llvm::Value *warpArg = nullptr;
-
-    if (m_procedurePrototype)
-        warpArg = m_function->getArg(4);
-
-    if (m_procedurePrototype && m_warp)
-        m_function->addFnAttr(llvm::Attribute::InlineHint);
-
     llvm::BasicBlock *entry = llvm::BasicBlock::Create(m_llvmCtx, "entry", m_function);
     llvm::BasicBlock *endBranch = llvm::BasicBlock::Create(m_llvmCtx, "end", m_function);
     m_builder.SetInsertPoint(entry);
@@ -96,7 +84,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
     std::vector<LLVMIfStatement> ifStatements;
     std::vector<LLVMLoop> loops;
 
-    m_utils.init(m_function, targetVariables, targetLists);
+    m_utils.init(m_function, m_procedurePrototype, m_warp);
 
     // Execute recorded instructions
     LLVMInstruction *ins = m_instructions.first();
@@ -108,18 +96,18 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 std::vector<llvm::Value *> args;
 
                 // Variables must be synchronized because the function can read them
-                m_utils.syncVariables(targetVariables);
+                m_utils.syncVariables(m_utils.targetVariables());
 
                 // Add execution context arg
                 if (ins->functionCtxArg) {
                     types.push_back(llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0));
-                    args.push_back(executionContextPtr);
+                    args.push_back(m_utils.executionContextPtr());
                 }
 
                 // Add target pointer arg
                 if (ins->functionTargetArg) {
                     types.push_back(llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0));
-                    args.push_back(targetPtr);
+                    args.push_back(m_utils.targetPtr());
                 }
 
                 // Args
@@ -200,7 +188,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 if (reg1->type() == Compiler::StaticType::Bool && reg2->type() == Compiler::StaticType::Bool) {
                     llvm::Value *bool1 = m_utils.castValue(arg1.second, Compiler::StaticType::Bool);
                     llvm::Value *bool2 = m_utils.castValue(arg2.second, Compiler::StaticType::Bool);
-                    ins->functionReturnReg->value = m_builder.CreateCall(m_utils.functions().resolve_llvm_random_bool(), { executionContextPtr, bool1, bool2 });
+                    ins->functionReturnReg->value = m_builder.CreateCall(m_utils.functions().resolve_llvm_random_bool(), { m_utils.executionContextPtr(), bool1, bool2 });
                 } else {
                     llvm::Constant *inf = llvm::ConstantFP::getInfinity(m_builder.getDoubleTy(), false);
                     llvm::Value *num1 = m_utils.removeNaN(m_utils.castValue(arg1.second, Compiler::StaticType::Number));
@@ -212,12 +200,12 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                     // NOTE: The random function will be called even in edge cases where it isn't needed, but they're rare, so it shouldn't be an issue
                     if (reg1->type() == Compiler::StaticType::Number && reg2->type() == Compiler::StaticType::Number)
                         ins->functionReturnReg->value =
-                            m_builder.CreateSelect(isInfOrNaN, sum, m_builder.CreateCall(m_utils.functions().resolve_llvm_random_double(), { executionContextPtr, num1, num2 }));
+                            m_builder.CreateSelect(isInfOrNaN, sum, m_builder.CreateCall(m_utils.functions().resolve_llvm_random_double(), { m_utils.executionContextPtr(), num1, num2 }));
                     else {
                         llvm::Value *value1 = m_utils.createValue(reg1);
                         llvm::Value *value2 = m_utils.createValue(reg2);
                         ins->functionReturnReg->value =
-                            m_builder.CreateSelect(isInfOrNaN, sum, m_builder.CreateCall(m_utils.functions().resolve_llvm_random(), { executionContextPtr, value1, value2 }));
+                            m_builder.CreateSelect(isInfOrNaN, sum, m_builder.CreateCall(m_utils.functions().resolve_llvm_random(), { m_utils.executionContextPtr(), value1, value2 }));
                     }
                 }
 
@@ -231,7 +219,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 const auto &arg2 = ins->args[1];
                 llvm::Value *from = m_builder.CreateFPToSI(m_utils.castValue(arg1.second, arg1.first), m_builder.getInt64Ty());
                 llvm::Value *to = m_builder.CreateFPToSI(m_utils.castValue(arg2.second, arg2.first), m_builder.getInt64Ty());
-                ins->functionReturnReg->value = m_builder.CreateCall(m_utils.functions().resolve_llvm_random_long(), { executionContextPtr, from, to });
+                ins->functionReturnReg->value = m_builder.CreateCall(m_utils.functions().resolve_llvm_random_long(), { m_utils.executionContextPtr(), from, to });
 
                 ins = ins->next;
                 break;
@@ -1039,7 +1027,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
             }
 
             case LLVMInstruction::Type::Yield:
-                createSuspend(coro.get(), warpArg, targetVariables);
+                createSuspend(coro.get(), m_utils.warpArg(), m_utils.targetVariables());
 
                 ins = ins->next;
                 break;
@@ -1282,7 +1270,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 assert(ins->procedurePrototype);
                 assert(ins->args.size() == ins->procedurePrototype->argumentTypes().size());
                 m_utils.freeScopeHeap();
-                m_utils.syncVariables(targetVariables);
+                m_utils.syncVariables(m_utils.targetVariables());
 
                 std::string name = getMainFunctionName(ins->procedurePrototype);
                 llvm::FunctionType *type = getMainFunctionType(ins->procedurePrototype);
@@ -1295,7 +1283,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                 if (m_warp)
                     args.push_back(m_builder.getInt1(true));
                 else
-                    args.push_back(m_procedurePrototype ? warpArg : m_builder.getInt1(false));
+                    args.push_back(m_utils.procedurePrototype() ? m_utils.warpArg() : m_builder.getInt1(false));
 
                 // Add procedure args
                 for (const auto &arg : ins->args) {
@@ -1313,14 +1301,14 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
                     m_builder.CreateCondBr(m_builder.CreateIsNull(handle), nextBranch, suspendBranch);
 
                     m_builder.SetInsertPoint(suspendBranch);
-                    createSuspend(coro.get(), warpArg, targetVariables);
+                    createSuspend(coro.get(), m_utils.warpArg(), m_utils.targetVariables());
                     llvm::Value *done = m_builder.CreateCall(m_ctx->coroutineResumeFunction(), { handle });
                     m_builder.CreateCondBr(done, nextBranch, suspendBranch);
 
                     m_builder.SetInsertPoint(nextBranch);
                 }
 
-                m_utils.reloadVariables(targetVariables);
+                m_utils.reloadVariables(m_utils.targetVariables());
 
                 ins = ins->next;
                 break;
@@ -1341,7 +1329,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
     m_builder.CreateBr(endBranch);
 
     m_builder.SetInsertPoint(endBranch);
-    m_utils.syncVariables(targetVariables);
+    m_utils.syncVariables(m_utils.targetVariables());
 
     // End and verify the function
     llvm::PointerType *pointerType = llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0);

From b53b497a77667fa64c0b432e9d109887c71f1c8b Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Mon, 4 Aug 2025 23:39:06 +0200
Subject: [PATCH 72/79] LLVMBuildUtils: Add LLVM module getter

---
 src/engine/internal/llvm/llvmbuildutils.cpp | 5 +++++
 src/engine/internal/llvm/llvmbuildutils.h   | 1 +
 2 files changed, 6 insertions(+)

diff --git a/src/engine/internal/llvm/llvmbuildutils.cpp b/src/engine/internal/llvm/llvmbuildutils.cpp
index c5bc14e9..005c3610 100644
--- a/src/engine/internal/llvm/llvmbuildutils.cpp
+++ b/src/engine/internal/llvm/llvmbuildutils.cpp
@@ -99,6 +99,11 @@ llvm::LLVMContext &LLVMBuildUtils::llvmCtx()
     return m_llvmCtx;
 }
 
+llvm::Module *LLVMBuildUtils::module() const
+{
+    return m_ctx->module();
+}
+
 llvm::IRBuilder<> &LLVMBuildUtils::builder()
 {
     return m_builder;
diff --git a/src/engine/internal/llvm/llvmbuildutils.h b/src/engine/internal/llvm/llvmbuildutils.h
index e36dbb8b..d6379c86 100644
--- a/src/engine/internal/llvm/llvmbuildutils.h
+++ b/src/engine/internal/llvm/llvmbuildutils.h
@@ -29,6 +29,7 @@ class LLVMBuildUtils
         void end();
 
         llvm::LLVMContext &llvmCtx();
+        llvm::Module *module() const;
         llvm::IRBuilder<> &builder();
         LLVMFunctions &functions();
 

From 4fb695e7b11b7f4e92d3b98e660dc055cb490f70 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Tue, 5 Aug 2025 00:11:28 +0200
Subject: [PATCH 73/79] LLVMBuildUtils: Add compiler context getter

---
 src/engine/internal/llvm/llvmbuildutils.cpp | 5 +++++
 src/engine/internal/llvm/llvmbuildutils.h   | 1 +
 2 files changed, 6 insertions(+)

diff --git a/src/engine/internal/llvm/llvmbuildutils.cpp b/src/engine/internal/llvm/llvmbuildutils.cpp
index 005c3610..89720ebd 100644
--- a/src/engine/internal/llvm/llvmbuildutils.cpp
+++ b/src/engine/internal/llvm/llvmbuildutils.cpp
@@ -94,6 +94,11 @@ void LLVMBuildUtils::end()
     freeScopeHeap();
 }
 
+LLVMCompilerContext *LLVMBuildUtils::compilerCtx() const
+{
+    return m_ctx;
+}
+
 llvm::LLVMContext &LLVMBuildUtils::llvmCtx()
 {
     return m_llvmCtx;
diff --git a/src/engine/internal/llvm/llvmbuildutils.h b/src/engine/internal/llvm/llvmbuildutils.h
index d6379c86..ee1c924a 100644
--- a/src/engine/internal/llvm/llvmbuildutils.h
+++ b/src/engine/internal/llvm/llvmbuildutils.h
@@ -28,6 +28,7 @@ class LLVMBuildUtils
         void init(llvm::Function *function, BlockPrototype *procedurePrototype, bool warp);
         void end();
 
+        LLVMCompilerContext *compilerCtx() const;
         llvm::LLVMContext &llvmCtx();
         llvm::Module *module() const;
         llvm::IRBuilder<> &builder();

From 763550659c82fbfb90e8c3430347389d470806a3 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Tue, 5 Aug 2025 00:11:45 +0200
Subject: [PATCH 74/79] LLVMBuildUtils: Add type analyzer

---
 src/engine/internal/llvm/llvmbuildutils.cpp | 5 +++++
 src/engine/internal/llvm/llvmbuildutils.h   | 3 +++
 2 files changed, 8 insertions(+)

diff --git a/src/engine/internal/llvm/llvmbuildutils.cpp b/src/engine/internal/llvm/llvmbuildutils.cpp
index 89720ebd..e384d9d0 100644
--- a/src/engine/internal/llvm/llvmbuildutils.cpp
+++ b/src/engine/internal/llvm/llvmbuildutils.cpp
@@ -119,6 +119,11 @@ LLVMFunctions &LLVMBuildUtils::functions()
     return m_functions;
 }
 
+LLVMTypeAnalyzer &LLVMBuildUtils::typeAnalyzer()
+{
+    return m_typeAnalyzer;
+}
+
 BlockPrototype *LLVMBuildUtils::procedurePrototype() const
 {
     return m_procedurePrototype;
diff --git a/src/engine/internal/llvm/llvmbuildutils.h b/src/engine/internal/llvm/llvmbuildutils.h
index ee1c924a..e680ea5d 100644
--- a/src/engine/internal/llvm/llvmbuildutils.h
+++ b/src/engine/internal/llvm/llvmbuildutils.h
@@ -7,6 +7,7 @@
 #include "llvmfunctions.h"
 #include "llvmvariableptr.h"
 #include "llvmlistptr.h"
+#include "llvmtypeanalyzer.h"
 
 namespace libscratchcpp
 {
@@ -33,6 +34,7 @@ class LLVMBuildUtils
         llvm::Module *module() const;
         llvm::IRBuilder<> &builder();
         LLVMFunctions &functions();
+        LLVMTypeAnalyzer &typeAnalyzer();
 
         BlockPrototype *procedurePrototype() const;
         bool warp() const;
@@ -96,6 +98,7 @@ class LLVMBuildUtils
         llvm::LLVMContext &m_llvmCtx;
         llvm::IRBuilder<> &m_builder;
         LLVMFunctions m_functions;
+        LLVMTypeAnalyzer m_typeAnalyzer;
         Target *m_target = nullptr;
         llvm::Function *m_function = nullptr;
 

From 3198ff4b18a9b1d811ef3b683903a582425f8ba5 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Tue, 5 Aug 2025 00:14:55 +0200
Subject: [PATCH 75/79] LLVMBuildUtils: Add script function getter

---
 src/engine/internal/llvm/llvmbuildutils.cpp | 5 +++++
 src/engine/internal/llvm/llvmbuildutils.h   | 1 +
 2 files changed, 6 insertions(+)

diff --git a/src/engine/internal/llvm/llvmbuildutils.cpp b/src/engine/internal/llvm/llvmbuildutils.cpp
index e384d9d0..e8116529 100644
--- a/src/engine/internal/llvm/llvmbuildutils.cpp
+++ b/src/engine/internal/llvm/llvmbuildutils.cpp
@@ -114,6 +114,11 @@ llvm::IRBuilder<> &LLVMBuildUtils::builder()
     return m_builder;
 }
 
+llvm::Function *LLVMBuildUtils::function() const
+{
+    return m_function;
+}
+
 LLVMFunctions &LLVMBuildUtils::functions()
 {
     return m_functions;
diff --git a/src/engine/internal/llvm/llvmbuildutils.h b/src/engine/internal/llvm/llvmbuildutils.h
index e680ea5d..0d7d593e 100644
--- a/src/engine/internal/llvm/llvmbuildutils.h
+++ b/src/engine/internal/llvm/llvmbuildutils.h
@@ -33,6 +33,7 @@ class LLVMBuildUtils
         llvm::LLVMContext &llvmCtx();
         llvm::Module *module() const;
         llvm::IRBuilder<> &builder();
+        llvm::Function *function() const;
         LLVMFunctions &functions();
         LLVMTypeAnalyzer &typeAnalyzer();
 

From c21ea7b548cea639dc3586b76c719d3e85bbaa80 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Tue, 5 Aug 2025 10:23:00 +0200
Subject: [PATCH 76/79] LLVMTypeAnalyzer: Add missing include guard

---
 src/engine/internal/llvm/llvmtypeanalyzer.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/engine/internal/llvm/llvmtypeanalyzer.h b/src/engine/internal/llvm/llvmtypeanalyzer.h
index 4244d2b8..a1d55377 100644
--- a/src/engine/internal/llvm/llvmtypeanalyzer.h
+++ b/src/engine/internal/llvm/llvmtypeanalyzer.h
@@ -1,5 +1,7 @@
 // SPDX-License-Identifier: Apache-2.0
 
+#pragma once
+
 #include <scratchcpp/compiler.h>
 #include <unordered_map>
 

From 0659c6a593dd685c15635e76aee730df45accb21 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Tue, 5 Aug 2025 12:46:35 +0200
Subject: [PATCH 77/79] Move LLVM instructions to separate classes

---
 .../internal/llvm/instructions/comparison.cpp |   81 +
 .../internal/llvm/instructions/comparison.h   |    7 +
 .../internal/llvm/instructions/control.cpp    |  336 ++++
 .../internal/llvm/instructions/control.h      |   14 +
 .../internal/llvm/instructions/functions.cpp  |   54 +
 .../internal/llvm/instructions/functions.h    |    3 +
 .../internal/llvm/instructions/lists.cpp      |  286 ++++
 src/engine/internal/llvm/instructions/lists.h |   12 +
 .../internal/llvm/instructions/logic.cpp      |   58 +
 src/engine/internal/llvm/instructions/logic.h |    5 +
 .../internal/llvm/instructions/math.cpp       |  457 ++++++
 src/engine/internal/llvm/instructions/math.h  |   24 +
 .../internal/llvm/instructions/procedures.cpp |   86 +
 .../internal/llvm/instructions/procedures.h   |    4 +
 .../internal/llvm/instructions/string.cpp     |  126 ++
 .../internal/llvm/instructions/string.h       |    5 +
 .../internal/llvm/instructions/variables.cpp  |  148 ++
 .../internal/llvm/instructions/variables.h    |    7 +
 src/engine/internal/llvm/llvmbuildutils.cpp   |  158 +-
 src/engine/internal/llvm/llvmbuildutils.h     |   28 +-
 src/engine/internal/llvm/llvmcodebuilder.cpp  | 1382 +----------------
 src/engine/internal/llvm/llvmcodebuilder.h    |   10 +-
 22 files changed, 1906 insertions(+), 1385 deletions(-)

diff --git a/src/engine/internal/llvm/instructions/comparison.cpp b/src/engine/internal/llvm/instructions/comparison.cpp
index 466d36db..9a76ce24 100644
--- a/src/engine/internal/llvm/instructions/comparison.cpp
+++ b/src/engine/internal/llvm/instructions/comparison.cpp
@@ -1,10 +1,91 @@
 // SPDX-License-Identifier: Apache-2.0
 
 #include "comparison.h"
+#include "../llvminstruction.h"
 #include "../llvmbuildutils.h"
 
+using namespace libscratchcpp;
 using namespace libscratchcpp::llvmins;
 
 ProcessResult Comparison::process(LLVMInstruction *ins)
 {
+    ProcessResult ret(true, ins);
+
+    switch (ins->type) {
+        case LLVMInstruction::Type::CmpEQ:
+            ret.next = buildCmpEQ(ins);
+            break;
+
+        case LLVMInstruction::Type::CmpGT:
+            ret.next = buildCmpGT(ins);
+            break;
+
+        case LLVMInstruction::Type::CmpLT:
+            ret.next = buildCmpLT(ins);
+            break;
+
+        case LLVMInstruction::Type::StrCmpEQCS:
+            ret.next = buildStrCmpEQCS(ins);
+            break;
+
+        case LLVMInstruction::Type::StrCmpEQCI:
+            ret.next = buildStrCmpEQCI(ins);
+            break;
+
+        default:
+            ret.match = false;
+            break;
+    }
+
+    return ret;
+}
+
+LLVMInstruction *Comparison::buildCmpEQ(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 2);
+    const auto &arg1 = ins->args[0].second;
+    const auto &arg2 = ins->args[1].second;
+    ins->functionReturnReg->value = m_utils.createComparison(arg1, arg2, LLVMBuildUtils::Comparison::EQ);
+
+    return ins->next;
+}
+
+LLVMInstruction *Comparison::buildCmpGT(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 2);
+    const auto &arg1 = ins->args[0].second;
+    const auto &arg2 = ins->args[1].second;
+    ins->functionReturnReg->value = m_utils.createComparison(arg1, arg2, LLVMBuildUtils::Comparison::GT);
+
+    return ins->next;
+}
+
+LLVMInstruction *Comparison::buildCmpLT(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 2);
+    const auto &arg1 = ins->args[0].second;
+    const auto &arg2 = ins->args[1].second;
+    ins->functionReturnReg->value = m_utils.createComparison(arg1, arg2, LLVMBuildUtils::Comparison::LT);
+
+    return ins->next;
+}
+
+LLVMInstruction *Comparison::buildStrCmpEQCS(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 2);
+    const auto &arg1 = ins->args[0].second;
+    const auto &arg2 = ins->args[1].second;
+    ins->functionReturnReg->value = m_utils.createStringComparison(arg1, arg2, true);
+
+    return ins->next;
+}
+
+LLVMInstruction *Comparison::buildStrCmpEQCI(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 2);
+    const auto &arg1 = ins->args[0].second;
+    const auto &arg2 = ins->args[1].second;
+    ins->functionReturnReg->value = m_utils.createStringComparison(arg1, arg2, false);
+
+    return ins->next;
 }
diff --git a/src/engine/internal/llvm/instructions/comparison.h b/src/engine/internal/llvm/instructions/comparison.h
index c1774c1d..0bc7f28e 100644
--- a/src/engine/internal/llvm/instructions/comparison.h
+++ b/src/engine/internal/llvm/instructions/comparison.h
@@ -13,6 +13,13 @@ class Comparison : public InstructionGroup
         using InstructionGroup::InstructionGroup;
 
         ProcessResult process(LLVMInstruction *ins) override;
+
+    private:
+        LLVMInstruction *buildCmpEQ(LLVMInstruction *ins);
+        LLVMInstruction *buildCmpGT(LLVMInstruction *ins);
+        LLVMInstruction *buildCmpLT(LLVMInstruction *ins);
+        LLVMInstruction *buildStrCmpEQCS(LLVMInstruction *ins);
+        LLVMInstruction *buildStrCmpEQCI(LLVMInstruction *ins);
 };
 
 } // namespace libscratchcpp::llvmins
diff --git a/src/engine/internal/llvm/instructions/control.cpp b/src/engine/internal/llvm/instructions/control.cpp
index 804212a9..d3b769af 100644
--- a/src/engine/internal/llvm/instructions/control.cpp
+++ b/src/engine/internal/llvm/instructions/control.cpp
@@ -1,10 +1,346 @@
 // SPDX-License-Identifier: Apache-2.0
 
 #include "control.h"
+#include "../llvminstruction.h"
 #include "../llvmbuildutils.h"
 
+using namespace libscratchcpp;
 using namespace libscratchcpp::llvmins;
 
 ProcessResult Control::process(LLVMInstruction *ins)
 {
+    ProcessResult ret(true, ins);
+
+    switch (ins->type) {
+        case LLVMInstruction::Type::Select:
+            ret.next = buildSelect(ins);
+            break;
+
+        case LLVMInstruction::Type::Yield:
+            ret.next = buildYield(ins);
+            break;
+
+        case LLVMInstruction::Type::BeginIf:
+            ret.next = buildBeginIf(ins);
+            break;
+
+        case LLVMInstruction::Type::BeginElse:
+            ret.next = buildBeginElse(ins);
+            break;
+
+        case LLVMInstruction::Type::EndIf:
+            ret.next = buildEndIf(ins);
+            break;
+
+        case LLVMInstruction::Type::BeginRepeatLoop:
+            ret.next = buildBeginRepeatLoop(ins);
+            break;
+
+        case LLVMInstruction::Type::LoopIndex:
+            ret.next = buildLoopIndex(ins);
+            break;
+
+        case LLVMInstruction::Type::BeginWhileLoop:
+            ret.next = buildBeginWhileLoop(ins);
+            break;
+
+        case LLVMInstruction::Type::BeginRepeatUntilLoop:
+            ret.next = buildBeginRepeatUntilLoop(ins);
+            break;
+
+        case LLVMInstruction::Type::BeginLoopCondition:
+            ret.next = buildBeginLoopCondition(ins);
+            break;
+
+        case LLVMInstruction::Type::EndLoop:
+            ret.next = buildEndLoop(ins);
+            break;
+
+        case LLVMInstruction::Type::Stop:
+            ret.next = buildStop(ins);
+            break;
+
+        default:
+            ret.match = false;
+            break;
+    }
+
+    return ret;
+}
+
+LLVMInstruction *Control::buildSelect(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 3);
+    const auto &arg1 = ins->args[0];
+    const auto &arg2 = ins->args[1];
+    const auto &arg3 = ins->args[2];
+    auto type = arg2.first;
+    llvm::Value *cond = m_utils.castValue(arg1.second, arg1.first);
+    llvm::Value *trueValue;
+    llvm::Value *falseValue;
+
+    if (type == Compiler::StaticType::Unknown) {
+        trueValue = m_utils.createValue(arg2.second);
+        falseValue = m_utils.createValue(arg3.second);
+    } else {
+        trueValue = m_utils.castValue(arg2.second, type);
+        falseValue = m_utils.castValue(arg3.second, type);
+    }
+
+    ins->functionReturnReg->value = m_builder.CreateSelect(cond, trueValue, falseValue);
+    return ins->next;
+}
+
+LLVMInstruction *Control::buildYield(LLVMInstruction *ins)
+{
+    m_utils.createSuspend();
+    return ins->next;
+}
+
+LLVMInstruction *Control::buildBeginIf(LLVMInstruction *ins)
+{
+    LLVMIfStatement statement;
+    statement.beforeIf = m_builder.GetInsertBlock();
+    statement.body = llvm::BasicBlock::Create(m_utils.llvmCtx(), "", m_utils.function());
+
+    // Use last reg
+    assert(ins->args.size() == 1);
+    const auto &reg = ins->args[0];
+    assert(reg.first == Compiler::StaticType::Bool);
+    statement.condition = m_utils.castValue(reg.second, reg.first);
+
+    // Switch to body branch
+    m_builder.SetInsertPoint(statement.body);
+
+    m_utils.ifStatements().push_back(statement);
+    m_utils.pushScopeLevel();
+
+    return ins->next;
+}
+
+LLVMInstruction *Control::buildBeginElse(LLVMInstruction *ins)
+{
+    llvm::LLVMContext &llvmCtx = m_utils.llvmCtx();
+    llvm::Function *function = m_utils.function();
+
+    assert(!m_utils.ifStatements().empty());
+    LLVMIfStatement &statement = m_utils.ifStatements().back();
+
+    // Jump to the branch after the if statement
+    assert(!statement.afterIf);
+    statement.afterIf = llvm::BasicBlock::Create(llvmCtx, "", function);
+    m_utils.freeScopeHeap();
+    m_builder.CreateBr(statement.afterIf);
+
+    // Create else branch
+    assert(!statement.elseBranch);
+    statement.elseBranch = llvm::BasicBlock::Create(llvmCtx, "", function);
+
+    // Since there's an else branch, the conditional instruction should jump to it
+    m_builder.SetInsertPoint(statement.beforeIf);
+    m_builder.CreateCondBr(statement.condition, statement.body, statement.elseBranch);
+
+    // Switch to the else branch
+    m_builder.SetInsertPoint(statement.elseBranch);
+
+    return ins->next;
+}
+
+LLVMInstruction *Control::buildEndIf(LLVMInstruction *ins)
+{
+    auto &ifStatements = m_utils.ifStatements();
+    assert(!ifStatements.empty());
+    LLVMIfStatement &statement = ifStatements.back();
+    m_utils.freeScopeHeap();
+
+    // Jump to the branch after the if statement
+    if (!statement.afterIf)
+        statement.afterIf = llvm::BasicBlock::Create(m_utils.llvmCtx(), "", m_utils.function());
+
+    m_builder.CreateBr(statement.afterIf);
+
+    if (statement.elseBranch) {
+    } else {
+        // If there wasn't an 'else' branch, create a conditional instruction which skips the if statement if false
+        m_builder.SetInsertPoint(statement.beforeIf);
+        m_builder.CreateCondBr(statement.condition, statement.body, statement.afterIf);
+    }
+
+    // Switch to the branch after the if statement
+    m_builder.SetInsertPoint(statement.afterIf);
+
+    ifStatements.pop_back();
+    m_utils.popScopeLevel();
+
+    return ins->next;
+}
+
+LLVMInstruction *Control::buildBeginRepeatLoop(LLVMInstruction *ins)
+{
+    llvm::LLVMContext &llvmCtx = m_utils.llvmCtx();
+    llvm::Function *function = m_utils.function();
+
+    LLVMLoop loop;
+    loop.isRepeatLoop = true;
+
+    // index = 0
+    llvm::Constant *zero = llvm::ConstantInt::get(m_builder.getInt64Ty(), 0, true);
+    loop.index = m_utils.addAlloca(m_builder.getInt64Ty());
+    m_builder.CreateStore(zero, loop.index);
+
+    // Create branches
+    llvm::BasicBlock *roundBranch = llvm::BasicBlock::Create(llvmCtx, "", function);
+    loop.conditionBranch = llvm::BasicBlock::Create(llvmCtx, "", function);
+    loop.afterLoop = llvm::BasicBlock::Create(llvmCtx, "", function);
+
+    // Use last reg for count
+    assert(ins->args.size() == 1);
+    const auto &reg = ins->args[0];
+    assert(reg.first == Compiler::StaticType::Number);
+    llvm::Value *count = m_utils.castValue(reg.second, reg.first);
+    llvm::Value *isInf = m_builder.CreateFCmpOEQ(count, llvm::ConstantFP::getInfinity(m_builder.getDoubleTy(), false));
+
+    // Clamp count if <= 0 (we can skip the loop if count is not positive)
+    llvm::Value *comparison = m_builder.CreateFCmpULE(count, llvm::ConstantFP::get(llvmCtx, llvm::APFloat(0.0)));
+    m_builder.CreateCondBr(comparison, loop.afterLoop, roundBranch);
+
+    // Round (Scratch-specific behavior)
+    m_builder.SetInsertPoint(roundBranch);
+    llvm::Function *roundFunc = llvm::Intrinsic::getDeclaration(m_utils.module(), llvm::Intrinsic::round, { count->getType() });
+    count = m_builder.CreateCall(roundFunc, { count });
+    count = m_builder.CreateFPToUI(count, m_builder.getInt64Ty()); // cast to unsigned integer
+    count = m_builder.CreateSelect(isInf, zero, count);
+
+    // Jump to condition branch
+    m_builder.CreateBr(loop.conditionBranch);
+
+    // Check index
+    m_builder.SetInsertPoint(loop.conditionBranch);
+
+    llvm::BasicBlock *body = llvm::BasicBlock::Create(llvmCtx, "", function);
+
+    if (!loop.afterLoop)
+        loop.afterLoop = llvm::BasicBlock::Create(llvmCtx, "", function);
+
+    llvm::Value *currentIndex = m_builder.CreateLoad(m_builder.getInt64Ty(), loop.index);
+    comparison = m_builder.CreateOr(isInf, m_builder.CreateICmpULT(currentIndex, count));
+    m_builder.CreateCondBr(comparison, body, loop.afterLoop);
+
+    // Switch to body branch
+    m_builder.SetInsertPoint(body);
+
+    m_utils.loops().push_back(loop);
+    m_utils.pushScopeLevel();
+
+    return ins->next;
+}
+
+LLVMInstruction *Control::buildLoopIndex(LLVMInstruction *ins)
+{
+    assert(!m_utils.loops().empty());
+    LLVMLoop &loop = m_utils.loops().back();
+    llvm::Value *index = m_builder.CreateLoad(m_builder.getInt64Ty(), loop.index);
+    ins->functionReturnReg->value = m_builder.CreateUIToFP(index, m_builder.getDoubleTy());
+
+    return ins->next;
+}
+
+LLVMInstruction *Control::buildBeginWhileLoop(LLVMInstruction *ins)
+{
+    llvm::LLVMContext &llvmCtx = m_utils.llvmCtx();
+    llvm::Function *function = m_utils.function();
+
+    assert(!m_utils.loops().empty());
+    LLVMLoop &loop = m_utils.loops().back();
+
+    // Create branches
+    llvm::BasicBlock *body = llvm::BasicBlock::Create(llvmCtx, "", function);
+    loop.afterLoop = llvm::BasicBlock::Create(llvmCtx, "", function);
+
+    // Use last reg
+    assert(ins->args.size() == 1);
+    const auto &reg = ins->args[0];
+    assert(reg.first == Compiler::StaticType::Bool);
+    llvm::Value *condition = m_utils.castValue(reg.second, reg.first);
+    m_builder.CreateCondBr(condition, body, loop.afterLoop);
+
+    // Switch to body branch
+    m_builder.SetInsertPoint(body);
+    m_utils.pushScopeLevel();
+
+    return ins->next;
+}
+
+LLVMInstruction *Control::buildBeginRepeatUntilLoop(LLVMInstruction *ins)
+{
+    llvm::LLVMContext &llvmCtx = m_utils.llvmCtx();
+    llvm::Function *function = m_utils.function();
+
+    assert(!m_utils.loops().empty());
+    LLVMLoop &loop = m_utils.loops().back();
+
+    // Create branches
+    llvm::BasicBlock *body = llvm::BasicBlock::Create(llvmCtx, "", function);
+    loop.afterLoop = llvm::BasicBlock::Create(llvmCtx, "", function);
+
+    // Use last reg
+    assert(ins->args.size() == 1);
+    const auto &reg = ins->args[0];
+    assert(reg.first == Compiler::StaticType::Bool);
+    llvm::Value *condition = m_utils.castValue(reg.second, reg.first);
+    m_builder.CreateCondBr(condition, loop.afterLoop, body);
+
+    // Switch to body branch
+    m_builder.SetInsertPoint(body);
+    m_utils.pushScopeLevel();
+
+    return ins->next;
+}
+
+LLVMInstruction *Control::buildBeginLoopCondition(LLVMInstruction *ins)
+{
+    LLVMLoop loop;
+    loop.isRepeatLoop = false;
+    loop.conditionBranch = llvm::BasicBlock::Create(m_utils.llvmCtx(), "", m_utils.function());
+    m_builder.CreateBr(loop.conditionBranch);
+    m_builder.SetInsertPoint(loop.conditionBranch);
+    m_utils.loops().push_back(loop);
+
+    return ins->next;
+}
+
+LLVMInstruction *Control::buildEndLoop(LLVMInstruction *ins)
+{
+    auto &loops = m_utils.loops();
+    assert(!loops.empty());
+    LLVMLoop &loop = loops.back();
+
+    if (loop.isRepeatLoop) {
+        // Increment index
+        llvm::Value *currentIndex = m_builder.CreateLoad(m_builder.getInt64Ty(), loop.index);
+        llvm::Value *incremented = m_builder.CreateAdd(currentIndex, llvm::ConstantInt::get(m_builder.getInt64Ty(), 1, false));
+        m_builder.CreateStore(incremented, loop.index);
+    }
+
+    // Jump to the condition branch
+    m_utils.freeScopeHeap();
+    m_builder.CreateBr(loop.conditionBranch);
+
+    // Switch to the branch after the loop
+    m_builder.SetInsertPoint(loop.afterLoop);
+
+    loops.pop_back();
+    m_utils.popScopeLevel();
+
+    return ins->next;
+}
+
+LLVMInstruction *Control::buildStop(LLVMInstruction *ins)
+{
+    m_utils.freeScopeHeap();
+    m_builder.CreateBr(m_utils.endBranch());
+    llvm::BasicBlock *nextBranch = llvm::BasicBlock::Create(m_utils.llvmCtx(), "", m_utils.function());
+    m_builder.SetInsertPoint(nextBranch);
+
+    return ins->next;
 }
diff --git a/src/engine/internal/llvm/instructions/control.h b/src/engine/internal/llvm/instructions/control.h
index 0769939c..0c80f817 100644
--- a/src/engine/internal/llvm/instructions/control.h
+++ b/src/engine/internal/llvm/instructions/control.h
@@ -13,6 +13,20 @@ class Control : public InstructionGroup
         using InstructionGroup::InstructionGroup;
 
         ProcessResult process(LLVMInstruction *ins) override;
+
+    private:
+        LLVMInstruction *buildSelect(LLVMInstruction *ins);
+        LLVMInstruction *buildYield(LLVMInstruction *ins);
+        LLVMInstruction *buildBeginIf(LLVMInstruction *ins);
+        LLVMInstruction *buildBeginElse(LLVMInstruction *ins);
+        LLVMInstruction *buildEndIf(LLVMInstruction *ins);
+        LLVMInstruction *buildBeginRepeatLoop(LLVMInstruction *ins);
+        LLVMInstruction *buildLoopIndex(LLVMInstruction *ins);
+        LLVMInstruction *buildBeginWhileLoop(LLVMInstruction *ins);
+        LLVMInstruction *buildBeginRepeatUntilLoop(LLVMInstruction *ins);
+        LLVMInstruction *buildBeginLoopCondition(LLVMInstruction *ins);
+        LLVMInstruction *buildEndLoop(LLVMInstruction *ins);
+        LLVMInstruction *buildStop(LLVMInstruction *ins);
 };
 
 } // namespace libscratchcpp::llvmins
diff --git a/src/engine/internal/llvm/instructions/functions.cpp b/src/engine/internal/llvm/instructions/functions.cpp
index ee9e830b..cc5c9679 100644
--- a/src/engine/internal/llvm/instructions/functions.cpp
+++ b/src/engine/internal/llvm/instructions/functions.cpp
@@ -1,10 +1,64 @@
 // SPDX-License-Identifier: Apache-2.0
 
 #include "functions.h"
+#include "../llvminstruction.h"
 #include "../llvmbuildutils.h"
 
+using namespace libscratchcpp;
 using namespace libscratchcpp::llvmins;
 
 ProcessResult Functions::process(LLVMInstruction *ins)
 {
+    ProcessResult ret(true, ins);
+
+    switch (ins->type) {
+        case LLVMInstruction::Type::FunctionCall:
+            ret.next = buildFunctionCall(ins);
+            break;
+
+        default:
+            ret.match = false;
+            break;
+    }
+
+    return ret;
+}
+
+LLVMInstruction *Functions::buildFunctionCall(LLVMInstruction *ins)
+{
+    std::vector<llvm::Type *> types;
+    std::vector<llvm::Value *> args;
+
+    // Variables must be synchronized because the function can read them
+    m_utils.syncVariables(m_utils.targetVariables());
+
+    // Add execution context arg
+    if (ins->functionCtxArg) {
+        types.push_back(llvm::PointerType::get(llvm::Type::getInt8Ty(m_utils.llvmCtx()), 0));
+        args.push_back(m_utils.executionContextPtr());
+    }
+
+    // Add target pointer arg
+    if (ins->functionTargetArg) {
+        types.push_back(llvm::PointerType::get(llvm::Type::getInt8Ty(m_utils.llvmCtx()), 0));
+        args.push_back(m_utils.targetPtr());
+    }
+
+    // Args
+    for (auto &arg : ins->args) {
+        types.push_back(m_utils.getType(arg.first));
+        args.push_back(m_utils.castValue(arg.second, arg.first));
+    }
+
+    llvm::Type *retType = m_utils.getType(ins->functionReturnReg ? ins->functionReturnReg->type() : Compiler::StaticType::Void);
+    llvm::Value *ret = m_builder.CreateCall(m_utils.functions().resolveFunction(ins->functionName, llvm::FunctionType::get(retType, types, false)), args);
+
+    if (ins->functionReturnReg) {
+        ins->functionReturnReg->value = ret;
+
+        if (ins->functionReturnReg->type() == Compiler::StaticType::String)
+            m_utils.freeStringLater(ins->functionReturnReg->value);
+    }
+
+    return ins->next;
 }
diff --git a/src/engine/internal/llvm/instructions/functions.h b/src/engine/internal/llvm/instructions/functions.h
index 6c18d2ad..2485ecbf 100644
--- a/src/engine/internal/llvm/instructions/functions.h
+++ b/src/engine/internal/llvm/instructions/functions.h
@@ -13,6 +13,9 @@ class Functions : public InstructionGroup
         using InstructionGroup::InstructionGroup;
 
         ProcessResult process(LLVMInstruction *ins) override;
+
+    private:
+        LLVMInstruction *buildFunctionCall(LLVMInstruction *ins);
 };
 
 } // namespace libscratchcpp::llvmins
diff --git a/src/engine/internal/llvm/instructions/lists.cpp b/src/engine/internal/llvm/instructions/lists.cpp
index 774d7c7c..5d83856b 100644
--- a/src/engine/internal/llvm/instructions/lists.cpp
+++ b/src/engine/internal/llvm/instructions/lists.cpp
@@ -1,10 +1,296 @@
 // SPDX-License-Identifier: Apache-2.0
 
 #include "lists.h"
+#include "../llvminstruction.h"
 #include "../llvmbuildutils.h"
+#include "../llvmconstantregister.h"
 
+using namespace libscratchcpp;
 using namespace libscratchcpp::llvmins;
 
 ProcessResult Lists::process(LLVMInstruction *ins)
 {
+    ProcessResult ret(true, ins);
+
+    switch (ins->type) {
+        case LLVMInstruction::Type::ClearList:
+            ret.next = buildClearList(ins);
+            break;
+
+        case LLVMInstruction::Type::RemoveListItem:
+            ret.next = buildRemoveListItem(ins);
+            break;
+
+        case LLVMInstruction::Type::AppendToList:
+            ret.next = buildAppendToList(ins);
+            break;
+
+        case LLVMInstruction::Type::InsertToList:
+            ret.next = buildInsertToList(ins);
+            break;
+
+        case LLVMInstruction::Type::ListReplace:
+            ret.next = buildListReplace(ins);
+            break;
+
+        case LLVMInstruction::Type::GetListContents:
+            ret.next = buildGetListContents(ins);
+            break;
+
+        case LLVMInstruction::Type::GetListItem:
+            ret.next = buildGetListItem(ins);
+            break;
+
+        case LLVMInstruction::Type::GetListSize:
+            ret.next = buildGetListSize(ins);
+            break;
+
+        case LLVMInstruction::Type::GetListItemIndex:
+            ret.next = buildGetListItemIndex(ins);
+            break;
+
+        case LLVMInstruction::Type::ListContainsItem:
+            ret.next = buildListContainsItem(ins);
+            break;
+
+        default:
+            ret.match = false;
+            break;
+    }
+
+    return ret;
+}
+
+LLVMInstruction *Lists::buildClearList(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 0);
+    LLVMListPtr &listPtr = m_utils.listPtr(ins->workList);
+    m_builder.CreateCall(m_utils.functions().resolve_list_clear(), listPtr.ptr);
+
+    return ins->next;
+}
+
+LLVMInstruction *Lists::buildRemoveListItem(LLVMInstruction *ins)
+{
+    llvm::LLVMContext &llvmCtx = m_utils.llvmCtx();
+    llvm::Function *function = m_utils.function();
+
+    assert(ins->args.size() == 1);
+    const auto &arg = ins->args[0];
+    LLVMListPtr &listPtr = m_utils.listPtr(ins->workList);
+
+    // Range check
+    llvm::Value *min = llvm::ConstantFP::get(llvmCtx, llvm::APFloat(0.0));
+    llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.sizePtr);
+    size = m_builder.CreateUIToFP(size, m_builder.getDoubleTy());
+    llvm::Value *index = m_utils.castValue(arg.second, arg.first);
+    llvm::Value *inRange = m_builder.CreateAnd(m_builder.CreateFCmpOGE(index, min), m_builder.CreateFCmpOLT(index, size));
+    llvm::BasicBlock *removeBlock = llvm::BasicBlock::Create(llvmCtx, "", function);
+    llvm::BasicBlock *nextBlock = llvm::BasicBlock::Create(llvmCtx, "", function);
+    m_builder.CreateCondBr(inRange, removeBlock, nextBlock);
+
+    // Remove
+    m_builder.SetInsertPoint(removeBlock);
+    index = m_builder.CreateFPToUI(m_utils.castValue(arg.second, arg.first), m_builder.getInt64Ty());
+    m_builder.CreateCall(m_utils.functions().resolve_list_remove(), { listPtr.ptr, index });
+    m_builder.CreateBr(nextBlock);
+
+    m_builder.SetInsertPoint(nextBlock);
+    return ins->next;
+}
+
+LLVMInstruction *Lists::buildAppendToList(LLVMInstruction *ins)
+{
+    llvm::LLVMContext &llvmCtx = m_utils.llvmCtx();
+    llvm::Function *function = m_utils.function();
+
+    assert(ins->args.size() == 1);
+    const auto &arg = ins->args[0];
+    Compiler::StaticType type = m_utils.optimizeRegisterType(arg.second);
+    LLVMListPtr &listPtr = m_utils.listPtr(ins->workList);
+
+    Compiler::StaticType listType = Compiler::StaticType::Unknown;
+
+    if (m_utils.warp())
+        listType = m_utils.typeAnalyzer().listType(ins->workList, ins, Compiler::StaticType::Unknown, false);
+
+    // Check if enough space is allocated
+    llvm::Value *allocatedSize = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.allocatedSizePtr);
+    llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.sizePtr);
+    llvm::Value *isAllocated = m_builder.CreateICmpUGT(allocatedSize, size);
+    llvm::BasicBlock *ifBlock = llvm::BasicBlock::Create(llvmCtx, "", function);
+    llvm::BasicBlock *elseBlock = llvm::BasicBlock::Create(llvmCtx, "", function);
+    llvm::BasicBlock *nextBlock = llvm::BasicBlock::Create(llvmCtx, "", function);
+    m_builder.CreateCondBr(isAllocated, ifBlock, elseBlock);
+
+    // If there's enough space, use the allocated memory
+    m_builder.SetInsertPoint(ifBlock);
+    llvm::Value *itemPtr = m_utils.getListItem(listPtr, size);
+    m_utils.createReusedValueStore(arg.second, itemPtr, type, listType);
+    m_builder.CreateStore(m_builder.CreateAdd(size, m_builder.getInt64(1)), listPtr.sizePtr);
+    m_builder.CreateBr(nextBlock);
+
+    // Otherwise call appendEmpty()
+    m_builder.SetInsertPoint(elseBlock);
+    itemPtr = m_builder.CreateCall(m_utils.functions().resolve_list_append_empty(), listPtr.ptr);
+    m_utils.createReusedValueStore(arg.second, itemPtr, type, listType);
+    m_builder.CreateBr(nextBlock);
+
+    m_builder.SetInsertPoint(nextBlock);
+    return ins->next;
+}
+
+LLVMInstruction *Lists::buildInsertToList(LLVMInstruction *ins)
+{
+    llvm::LLVMContext &llvmCtx = m_utils.llvmCtx();
+    llvm::Function *function = m_utils.function();
+
+    assert(ins->args.size() == 2);
+    const auto &indexArg = ins->args[0];
+    const auto &valueArg = ins->args[1];
+    Compiler::StaticType type = m_utils.optimizeRegisterType(valueArg.second);
+    LLVMListPtr &listPtr = m_utils.listPtr(ins->workList);
+
+    Compiler::StaticType listType = Compiler::StaticType::Unknown;
+
+    if (m_utils.warp())
+        listType = m_utils.typeAnalyzer().listType(ins->workList, ins, Compiler::StaticType::Unknown, false);
+
+    // Range check
+    llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.sizePtr);
+    llvm::Value *min = llvm::ConstantFP::get(llvmCtx, llvm::APFloat(0.0));
+    size = m_builder.CreateUIToFP(size, m_builder.getDoubleTy());
+    llvm::Value *index = m_utils.castValue(indexArg.second, indexArg.first);
+    llvm::Value *inRange = m_builder.CreateAnd(m_builder.CreateFCmpOGE(index, min), m_builder.CreateFCmpOLE(index, size));
+    llvm::BasicBlock *insertBlock = llvm::BasicBlock::Create(llvmCtx, "", function);
+    llvm::BasicBlock *nextBlock = llvm::BasicBlock::Create(llvmCtx, "", function);
+    m_builder.CreateCondBr(inRange, insertBlock, nextBlock);
+
+    // Insert
+    m_builder.SetInsertPoint(insertBlock);
+    index = m_builder.CreateFPToUI(index, m_builder.getInt64Ty());
+    llvm::Value *itemPtr = m_builder.CreateCall(m_utils.functions().resolve_list_insert_empty(), { listPtr.ptr, index });
+    m_utils.createReusedValueStore(valueArg.second, itemPtr, type, listType);
+
+    m_builder.CreateBr(nextBlock);
+
+    m_builder.SetInsertPoint(nextBlock);
+    return ins->next;
+}
+
+LLVMInstruction *Lists::buildListReplace(LLVMInstruction *ins)
+{
+    llvm::LLVMContext &llvmCtx = m_utils.llvmCtx();
+    llvm::Function *function = m_utils.function();
+
+    assert(ins->args.size() == 2);
+    const auto &indexArg = ins->args[0];
+    const auto &valueArg = ins->args[1];
+    Compiler::StaticType type = m_utils.optimizeRegisterType(valueArg.second);
+    LLVMListPtr &listPtr = m_utils.listPtr(ins->workList);
+
+    Compiler::StaticType listType = Compiler::StaticType::Unknown;
+
+    if (m_utils.warp())
+        listType = m_utils.typeAnalyzer().listType(ins->workList, ins, Compiler::StaticType::Unknown, false);
+
+    // Range check
+    llvm::Value *min = llvm::ConstantFP::get(llvmCtx, llvm::APFloat(0.0));
+    llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.sizePtr);
+    size = m_builder.CreateUIToFP(size, m_builder.getDoubleTy());
+    llvm::Value *index = m_utils.castValue(indexArg.second, indexArg.first);
+    llvm::Value *inRange = m_builder.CreateAnd(m_builder.CreateFCmpOGE(index, min), m_builder.CreateFCmpOLT(index, size));
+    llvm::BasicBlock *replaceBlock = llvm::BasicBlock::Create(llvmCtx, "", function);
+    llvm::BasicBlock *nextBlock = llvm::BasicBlock::Create(llvmCtx, "", function);
+    m_builder.CreateCondBr(inRange, replaceBlock, nextBlock);
+
+    // Replace
+    m_builder.SetInsertPoint(replaceBlock);
+    index = m_builder.CreateFPToUI(index, m_builder.getInt64Ty());
+    llvm::Value *itemPtr = m_utils.getListItem(listPtr, index);
+    m_utils.createValueStore(valueArg.second, itemPtr, type, listType);
+    m_builder.CreateBr(nextBlock);
+
+    m_builder.SetInsertPoint(nextBlock);
+    return ins->next;
+}
+
+LLVMInstruction *Lists::buildGetListContents(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 0);
+    const LLVMListPtr &listPtr = m_utils.listPtr(ins->workList);
+    llvm::Value *ptr = m_builder.CreateCall(m_utils.functions().resolve_list_to_string(), listPtr.ptr);
+    m_utils.freeStringLater(ptr);
+    ins->functionReturnReg->value = ptr;
+
+    return ins->next;
+}
+
+LLVMInstruction *Lists::buildGetListItem(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 1);
+    const auto &arg = ins->args[0];
+    LLVMListPtr &listPtr = m_utils.listPtr(ins->workList);
+
+    Compiler::StaticType listType = Compiler::StaticType::Unknown;
+
+    if (m_utils.warp())
+        listType = m_utils.typeAnalyzer().listType(ins->workList, ins, Compiler::StaticType::Unknown, false);
+
+    llvm::Value *min = llvm::ConstantFP::get(m_utils.llvmCtx(), llvm::APFloat(0.0));
+    llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.sizePtr);
+    size = m_builder.CreateUIToFP(size, m_builder.getDoubleTy());
+    llvm::Value *index = m_utils.castValue(arg.second, arg.first);
+    llvm::Value *inRange = m_builder.CreateAnd(m_builder.CreateFCmpOGE(index, min), m_builder.CreateFCmpOLT(index, size));
+
+    LLVMConstantRegister nullReg(listType == Compiler::StaticType::Unknown ? Compiler::StaticType::Number : listType, Value());
+    llvm::Value *null = m_utils.createValue(static_cast<LLVMRegister *>(&nullReg));
+
+    index = m_builder.CreateFPToUI(index, m_builder.getInt64Ty());
+    ins->functionReturnReg->value = m_builder.CreateSelect(inRange, m_utils.getListItem(listPtr, index), null);
+    ins->functionReturnReg->setType(listType);
+
+    return ins->next;
+}
+
+LLVMInstruction *Lists::buildGetListSize(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 0);
+    const LLVMListPtr &listPtr = m_utils.listPtr(ins->workList);
+    llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.sizePtr);
+    ins->functionReturnReg->value = m_builder.CreateUIToFP(size, m_builder.getDoubleTy());
+
+    return ins->next;
+}
+
+LLVMInstruction *Lists::buildGetListItemIndex(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 1);
+    const auto &arg = ins->args[0];
+    LLVMListPtr &listPtr = m_utils.listPtr(ins->workList);
+
+    Compiler::StaticType listType = Compiler::StaticType::Unknown;
+
+    if (m_utils.warp())
+        listType = m_utils.typeAnalyzer().listType(ins->workList, ins, Compiler::StaticType::Unknown, false);
+
+    ins->functionReturnReg->value = m_builder.CreateSIToFP(m_utils.getListItemIndex(listPtr, listType, arg.second), m_builder.getDoubleTy());
+    return ins->next;
+}
+
+LLVMInstruction *Lists::buildListContainsItem(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 1);
+    const auto &arg = ins->args[0];
+    LLVMListPtr &listPtr = m_utils.listPtr(ins->workList);
+
+    Compiler::StaticType listType = Compiler::StaticType::Unknown;
+
+    if (m_utils.warp())
+        listType = m_utils.typeAnalyzer().listType(ins->workList, ins, Compiler::StaticType::Unknown, false);
+
+    llvm::Value *index = m_utils.getListItemIndex(listPtr, listType, arg.second);
+    ins->functionReturnReg->value = m_builder.CreateICmpSGT(index, llvm::ConstantInt::get(m_builder.getInt64Ty(), -1, true));
+
+    return ins->next;
 }
diff --git a/src/engine/internal/llvm/instructions/lists.h b/src/engine/internal/llvm/instructions/lists.h
index 31b4b9cc..59aed889 100644
--- a/src/engine/internal/llvm/instructions/lists.h
+++ b/src/engine/internal/llvm/instructions/lists.h
@@ -13,6 +13,18 @@ class Lists : public InstructionGroup
         using InstructionGroup::InstructionGroup;
 
         ProcessResult process(LLVMInstruction *ins) override;
+
+    private:
+        LLVMInstruction *buildClearList(LLVMInstruction *ins);
+        LLVMInstruction *buildRemoveListItem(LLVMInstruction *ins);
+        LLVMInstruction *buildAppendToList(LLVMInstruction *ins);
+        LLVMInstruction *buildInsertToList(LLVMInstruction *ins);
+        LLVMInstruction *buildListReplace(LLVMInstruction *ins);
+        LLVMInstruction *buildGetListContents(LLVMInstruction *ins);
+        LLVMInstruction *buildGetListItem(LLVMInstruction *ins);
+        LLVMInstruction *buildGetListSize(LLVMInstruction *ins);
+        LLVMInstruction *buildGetListItemIndex(LLVMInstruction *ins);
+        LLVMInstruction *buildListContainsItem(LLVMInstruction *ins);
 };
 
 } // namespace libscratchcpp::llvmins
diff --git a/src/engine/internal/llvm/instructions/logic.cpp b/src/engine/internal/llvm/instructions/logic.cpp
index 68e73da0..e4410286 100644
--- a/src/engine/internal/llvm/instructions/logic.cpp
+++ b/src/engine/internal/llvm/instructions/logic.cpp
@@ -1,10 +1,68 @@
 // SPDX-License-Identifier: Apache-2.0
 
 #include "logic.h"
+#include "../llvminstruction.h"
 #include "../llvmbuildutils.h"
 
+using namespace libscratchcpp;
 using namespace libscratchcpp::llvmins;
 
 ProcessResult Logic::process(LLVMInstruction *ins)
 {
+    ProcessResult ret(true, ins);
+
+    switch (ins->type) {
+        case LLVMInstruction::Type::And:
+            ret.next = buildAnd(ins);
+            break;
+
+        case LLVMInstruction::Type::Or:
+            ret.next = buildOr(ins);
+            break;
+
+        case LLVMInstruction::Type::Not:
+            ret.next = buildNot(ins);
+            break;
+
+        default:
+            ret.match = false;
+            ret.next = (ins);
+            break;
+    }
+
+    return ret;
+}
+
+LLVMInstruction *Logic::buildAnd(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 2);
+    const auto &arg1 = ins->args[0];
+    const auto &arg2 = ins->args[1];
+    llvm::Value *bool1 = m_utils.castValue(arg1.second, arg1.first);
+    llvm::Value *bool2 = m_utils.castValue(arg2.second, arg2.first);
+    ins->functionReturnReg->value = m_builder.CreateAnd(bool1, bool2);
+
+    return ins->next;
+}
+
+LLVMInstruction *Logic::buildOr(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 2);
+    const auto &arg1 = ins->args[0];
+    const auto &arg2 = ins->args[1];
+    llvm::Value *bool1 = m_utils.castValue(arg1.second, arg1.first);
+    llvm::Value *bool2 = m_utils.castValue(arg2.second, arg2.first);
+    ins->functionReturnReg->value = m_builder.CreateOr(bool1, bool2);
+
+    return ins->next;
+}
+
+LLVMInstruction *Logic::buildNot(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 1);
+    const auto &arg = ins->args[0];
+    llvm::Value *value = m_utils.castValue(arg.second, arg.first);
+    ins->functionReturnReg->value = m_builder.CreateNot(value);
+
+    return ins->next;
 }
diff --git a/src/engine/internal/llvm/instructions/logic.h b/src/engine/internal/llvm/instructions/logic.h
index 0df01551..8ad284da 100644
--- a/src/engine/internal/llvm/instructions/logic.h
+++ b/src/engine/internal/llvm/instructions/logic.h
@@ -13,6 +13,11 @@ class Logic : public InstructionGroup
         using InstructionGroup::InstructionGroup;
 
         ProcessResult process(LLVMInstruction *ins) override;
+
+    private:
+        LLVMInstruction *buildAnd(LLVMInstruction *ins);
+        LLVMInstruction *buildOr(LLVMInstruction *ins);
+        LLVMInstruction *buildNot(LLVMInstruction *ins);
 };
 
 } // namespace libscratchcpp::llvmins
diff --git a/src/engine/internal/llvm/instructions/math.cpp b/src/engine/internal/llvm/instructions/math.cpp
index 78312657..1a6c452c 100644
--- a/src/engine/internal/llvm/instructions/math.cpp
+++ b/src/engine/internal/llvm/instructions/math.cpp
@@ -1,10 +1,467 @@
 // SPDX-License-Identifier: Apache-2.0
 
 #include "math.h"
+#include "../llvminstruction.h"
 #include "../llvmbuildutils.h"
 
+using namespace libscratchcpp;
 using namespace libscratchcpp::llvmins;
 
 ProcessResult Math::process(LLVMInstruction *ins)
 {
+    ProcessResult ret(true, ins);
+
+    switch (ins->type) {
+        case LLVMInstruction::Type::Add:
+            ret.next = buildAdd(ins);
+            break;
+
+        case LLVMInstruction::Type::Sub:
+            ret.next = buildSub(ins);
+            break;
+
+        case LLVMInstruction::Type::Mul:
+            ret.next = buildMul(ins);
+            break;
+
+        case LLVMInstruction::Type::Div:
+            ret.next = buildDiv(ins);
+            break;
+
+        case LLVMInstruction::Type::Random:
+            ret.next = buildRandom(ins);
+            break;
+
+        case LLVMInstruction::Type::RandomInt:
+            ret.next = buildRandomInt(ins);
+            break;
+
+        case LLVMInstruction::Type::Mod:
+            ret.next = buildMod(ins);
+            break;
+
+        case LLVMInstruction::Type::Round:
+            ret.next = buildRound(ins);
+            break;
+
+        case LLVMInstruction::Type::Abs:
+            ret.next = buildAbs(ins);
+            break;
+
+        case LLVMInstruction::Type::Floor:
+            ret.next = buildFloor(ins);
+            break;
+
+        case LLVMInstruction::Type::Ceil:
+            ret.next = buildCeil(ins);
+            break;
+
+        case LLVMInstruction::Type::Sqrt:
+            ret.next = buildSqrt(ins);
+            break;
+
+        case LLVMInstruction::Type::Sin:
+            ret.next = buildSin(ins);
+            break;
+
+        case LLVMInstruction::Type::Cos:
+            ret.next = buildCos(ins);
+            break;
+
+        case LLVMInstruction::Type::Tan:
+            ret.next = buildTan(ins);
+            break;
+
+        case LLVMInstruction::Type::Asin:
+            ret.next = buildAsin(ins);
+            break;
+
+        case LLVMInstruction::Type::Acos:
+            ret.next = buildAcos(ins);
+            break;
+
+        case LLVMInstruction::Type::Atan:
+            ret.next = buildAtan(ins);
+            break;
+
+        case LLVMInstruction::Type::Ln:
+            ret.next = buildLn(ins);
+            break;
+
+        case LLVMInstruction::Type::Log10:
+            ret.next = buildLog10(ins);
+            break;
+
+        case LLVMInstruction::Type::Exp:
+            ret.next = buildExp(ins);
+            break;
+
+        case LLVMInstruction::Type::Exp10:
+            ret.next = buildExp10(ins);
+            break;
+
+        default:
+            ret.match = false;
+            break;
+    }
+
+    return ret;
+}
+
+LLVMInstruction *Math::buildAdd(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 2);
+    const auto &arg1 = ins->args[0];
+    const auto &arg2 = ins->args[1];
+    llvm::Value *num1 = m_utils.removeNaN(m_utils.castValue(arg1.second, arg1.first));
+    llvm::Value *num2 = m_utils.removeNaN(m_utils.castValue(arg2.second, arg2.first));
+    ins->functionReturnReg->value = m_builder.CreateFAdd(num1, num2);
+
+    return ins->next;
+}
+
+LLVMInstruction *Math::buildSub(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 2);
+    const auto &arg1 = ins->args[0];
+    const auto &arg2 = ins->args[1];
+    llvm::Value *num1 = m_utils.removeNaN(m_utils.castValue(arg1.second, arg1.first));
+    llvm::Value *num2 = m_utils.removeNaN(m_utils.castValue(arg2.second, arg2.first));
+    ins->functionReturnReg->value = m_builder.CreateFSub(num1, num2);
+
+    return ins->next;
+}
+
+LLVMInstruction *Math::buildMul(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 2);
+    const auto &arg1 = ins->args[0];
+    const auto &arg2 = ins->args[1];
+    llvm::Value *num1 = m_utils.removeNaN(m_utils.castValue(arg1.second, arg1.first));
+    llvm::Value *num2 = m_utils.removeNaN(m_utils.castValue(arg2.second, arg2.first));
+    ins->functionReturnReg->value = m_builder.CreateFMul(num1, num2);
+
+    return ins->next;
+}
+
+LLVMInstruction *Math::buildDiv(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 2);
+    const auto &arg1 = ins->args[0];
+    const auto &arg2 = ins->args[1];
+    llvm::Value *num1 = m_utils.removeNaN(m_utils.castValue(arg1.second, arg1.first));
+    llvm::Value *num2 = m_utils.removeNaN(m_utils.castValue(arg2.second, arg2.first));
+    ins->functionReturnReg->value = m_builder.CreateFDiv(num1, num2);
+
+    return ins->next;
+}
+
+LLVMInstruction *Math::buildRandom(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 2);
+    const auto &arg1 = ins->args[0];
+    const auto &arg2 = ins->args[1];
+    LLVMRegister *reg1 = arg1.second;
+    LLVMRegister *reg2 = arg2.second;
+
+    if (reg1->type() == Compiler::StaticType::Bool && reg2->type() == Compiler::StaticType::Bool) {
+        llvm::Value *bool1 = m_utils.castValue(arg1.second, Compiler::StaticType::Bool);
+        llvm::Value *bool2 = m_utils.castValue(arg2.second, Compiler::StaticType::Bool);
+        ins->functionReturnReg->value = m_builder.CreateCall(m_utils.functions().resolve_llvm_random_bool(), { m_utils.executionContextPtr(), bool1, bool2 });
+    } else {
+        llvm::Constant *inf = llvm::ConstantFP::getInfinity(m_builder.getDoubleTy(), false);
+        llvm::Value *num1 = m_utils.removeNaN(m_utils.castValue(arg1.second, Compiler::StaticType::Number));
+        llvm::Value *num2 = m_utils.removeNaN(m_utils.castValue(arg2.second, Compiler::StaticType::Number));
+        llvm::Value *sum = m_builder.CreateFAdd(num1, num2);
+        llvm::Value *sumDiv = m_builder.CreateFDiv(sum, inf);
+        llvm::Value *isInfOrNaN = m_utils.isNaN(sumDiv);
+
+        // NOTE: The random function will be called even in edge cases where it isn't needed, but they're rare, so it shouldn't be an issue
+        if (reg1->type() == Compiler::StaticType::Number && reg2->type() == Compiler::StaticType::Number)
+            ins->functionReturnReg->value =
+                m_builder.CreateSelect(isInfOrNaN, sum, m_builder.CreateCall(m_utils.functions().resolve_llvm_random_double(), { m_utils.executionContextPtr(), num1, num2 }));
+        else {
+            llvm::Value *value1 = m_utils.createValue(reg1);
+            llvm::Value *value2 = m_utils.createValue(reg2);
+            ins->functionReturnReg->value = m_builder.CreateSelect(isInfOrNaN, sum, m_builder.CreateCall(m_utils.functions().resolve_llvm_random(), { m_utils.executionContextPtr(), value1, value2 }));
+        }
+    }
+
+    return ins->next;
+}
+
+LLVMInstruction *Math::buildRandomInt(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 2);
+    const auto &arg1 = ins->args[0];
+    const auto &arg2 = ins->args[1];
+    llvm::Value *from = m_builder.CreateFPToSI(m_utils.castValue(arg1.second, arg1.first), m_builder.getInt64Ty());
+    llvm::Value *to = m_builder.CreateFPToSI(m_utils.castValue(arg2.second, arg2.first), m_builder.getInt64Ty());
+    ins->functionReturnReg->value = m_builder.CreateCall(m_utils.functions().resolve_llvm_random_long(), { m_utils.executionContextPtr(), from, to });
+
+    return ins->next;
+}
+
+LLVMInstruction *Math::buildMod(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 2);
+    const auto &arg1 = ins->args[0];
+    const auto &arg2 = ins->args[1];
+    // rem(a, b) / b < 0.0 ? rem(a, b) + b : rem(a, b)
+    llvm::Constant *zero = llvm::ConstantFP::get(m_utils.llvmCtx(), llvm::APFloat(0.0));
+    llvm::Value *num1 = m_utils.removeNaN(m_utils.castValue(arg1.second, arg1.first));
+    llvm::Value *num2 = m_utils.removeNaN(m_utils.castValue(arg2.second, arg2.first));
+    llvm::Value *value = m_builder.CreateFRem(num1, num2);                                // rem(a, b)
+    llvm::Value *cond = m_builder.CreateFCmpOLT(m_builder.CreateFDiv(value, num2), zero); // rem(a, b) / b < 0.0                                                            // rem(a, b)
+    ins->functionReturnReg->value = m_builder.CreateSelect(cond, m_builder.CreateFAdd(value, num2), value);
+
+    return ins->next;
+}
+
+LLVMInstruction *Math::buildRound(LLVMInstruction *ins)
+{
+    llvm::LLVMContext &llvmCtx = m_utils.llvmCtx();
+    llvm::Module *module = m_utils.module();
+
+    assert(ins->args.size() == 1);
+    const auto &arg = ins->args[0];
+    // x >= 0.0 ? round(x) : (x >= -0.5 ? -0.0 : floor(x + 0.5))
+    llvm::Constant *zero = llvm::ConstantFP::get(llvmCtx, llvm::APFloat(0.0));
+    llvm::Constant *negativeZero = llvm::ConstantFP::get(llvmCtx, llvm::APFloat(-0.0));
+    llvm::Function *roundFunc = llvm::Intrinsic::getDeclaration(module, llvm::Intrinsic::round, m_builder.getDoubleTy());
+    llvm::Function *floorFunc = llvm::Intrinsic::getDeclaration(module, llvm::Intrinsic::floor, m_builder.getDoubleTy());
+    llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
+    llvm::Value *notNegative = m_builder.CreateFCmpOGE(num, zero);                                                                               // num >= 0.0
+    llvm::Value *roundNum = m_builder.CreateCall(roundFunc, num);                                                                                // round(num)
+    llvm::Value *negativeCond = m_builder.CreateFCmpOGE(num, llvm::ConstantFP::get(llvmCtx, llvm::APFloat(-0.5)));                               // num >= -0.5
+    llvm::Value *negativeRound = m_builder.CreateCall(floorFunc, m_builder.CreateFAdd(num, llvm::ConstantFP::get(llvmCtx, llvm::APFloat(0.5)))); // floor(x + 0.5)
+    ins->functionReturnReg->value = m_builder.CreateSelect(notNegative, roundNum, m_builder.CreateSelect(negativeCond, negativeZero, negativeRound));
+
+    return ins->next;
+}
+
+LLVMInstruction *Math::buildAbs(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 1);
+    const auto &arg = ins->args[0];
+    llvm::Function *absFunc = llvm::Intrinsic::getDeclaration(m_utils.module(), llvm::Intrinsic::fabs, m_builder.getDoubleTy());
+    llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
+    ins->functionReturnReg->value = m_builder.CreateCall(absFunc, num);
+
+    return ins->next;
+}
+
+LLVMInstruction *Math::buildFloor(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 1);
+    const auto &arg = ins->args[0];
+    llvm::Function *floorFunc = llvm::Intrinsic::getDeclaration(m_utils.module(), llvm::Intrinsic::floor, m_builder.getDoubleTy());
+    llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
+    ins->functionReturnReg->value = m_builder.CreateCall(floorFunc, num);
+
+    return ins->next;
+}
+
+LLVMInstruction *Math::buildCeil(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 1);
+    const auto &arg = ins->args[0];
+    llvm::Function *ceilFunc = llvm::Intrinsic::getDeclaration(m_utils.module(), llvm::Intrinsic::ceil, m_builder.getDoubleTy());
+    llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
+    ins->functionReturnReg->value = m_builder.CreateCall(ceilFunc, num);
+
+    return ins->next;
+}
+
+LLVMInstruction *Math::buildSqrt(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 1);
+    const auto &arg = ins->args[0];
+    // sqrt(x) + 0.0
+    // This avoids negative zero
+    llvm::Constant *zero = llvm::ConstantFP::get(m_utils.llvmCtx(), llvm::APFloat(0.0));
+    llvm::Function *sqrtFunc = llvm::Intrinsic::getDeclaration(m_utils.module(), llvm::Intrinsic::sqrt, m_builder.getDoubleTy());
+    llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
+    ins->functionReturnReg->value = m_builder.CreateFAdd(m_builder.CreateCall(sqrtFunc, num), zero);
+
+    return ins->next;
+}
+
+LLVMInstruction *Math::buildSin(LLVMInstruction *ins)
+{
+    llvm::LLVMContext &llvmCtx = m_utils.llvmCtx();
+    llvm::Module *module = m_utils.module();
+
+    assert(ins->args.size() == 1);
+    const auto &arg = ins->args[0];
+    // round(sin(x * pi / 180.0) * 1e10) / 1e10 + 0.0
+    // +0.0 to avoid -0.0
+    llvm::Constant *zero = llvm::ConstantFP::get(llvmCtx, llvm::APFloat(0.0));
+    llvm::Constant *pi = llvm::ConstantFP::get(llvmCtx, llvm::APFloat(std::acos(-1.0)));
+    llvm::Constant *piDeg = llvm::ConstantFP::get(llvmCtx, llvm::APFloat(180.0));
+    llvm::Constant *factor = llvm::ConstantFP::get(llvmCtx, llvm::APFloat(1e10));
+    llvm::Function *sinFunc = llvm::Intrinsic::getDeclaration(module, llvm::Intrinsic::sin, m_builder.getDoubleTy());
+    llvm::Function *roundFunc = llvm::Intrinsic::getDeclaration(module, llvm::Intrinsic::round, m_builder.getDoubleTy());
+    llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
+    llvm::Value *sinResult = m_builder.CreateCall(sinFunc, m_builder.CreateFDiv(m_builder.CreateFMul(num, pi), piDeg)); // sin(x * pi / 180)
+    llvm::Value *rounded = m_builder.CreateCall(roundFunc, m_builder.CreateFMul(sinResult, factor));                    // round(sin(x * 180) * 1e10)
+    ins->functionReturnReg->value = m_builder.CreateFAdd(m_builder.CreateFDiv(rounded, factor), zero);
+
+    return ins->next;
+}
+
+LLVMInstruction *Math::buildCos(LLVMInstruction *ins)
+{
+    llvm::LLVMContext &llvmCtx = m_utils.llvmCtx();
+    llvm::Module *module = m_utils.module();
+
+    assert(ins->args.size() == 1);
+    const auto &arg = ins->args[0];
+    // round(cos(x * pi / 180.0) * 1e10) / 1e10
+    llvm::Constant *pi = llvm::ConstantFP::get(llvmCtx, llvm::APFloat(std::acos(-1.0)));
+    llvm::Constant *piDeg = llvm::ConstantFP::get(llvmCtx, llvm::APFloat(180.0));
+    llvm::Constant *factor = llvm::ConstantFP::get(llvmCtx, llvm::APFloat(1e10));
+    llvm::Function *cosFunc = llvm::Intrinsic::getDeclaration(module, llvm::Intrinsic::cos, m_builder.getDoubleTy());
+    llvm::Function *roundFunc = llvm::Intrinsic::getDeclaration(module, llvm::Intrinsic::round, m_builder.getDoubleTy());
+    llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
+    llvm::Value *cosResult = m_builder.CreateCall(cosFunc, m_builder.CreateFDiv(m_builder.CreateFMul(num, pi), piDeg)); // cos(x * pi / 180)
+    llvm::Value *rounded = m_builder.CreateCall(roundFunc, m_builder.CreateFMul(cosResult, factor));                    // round(cos(x * 180) * 1e10)
+    ins->functionReturnReg->value = m_builder.CreateFDiv(rounded, factor);
+
+    return ins->next;
+}
+
+LLVMInstruction *Math::buildTan(LLVMInstruction *ins)
+{
+    llvm::LLVMContext &llvmCtx = m_utils.llvmCtx();
+    llvm::Module *module = m_utils.module();
+
+    assert(ins->args.size() == 1);
+    const auto &arg = ins->args[0];
+    // ((mod = rem(x, 360.0)) == -270.0 || mod == 90.0) ? inf : ((mod == -90.0 || mod == 270.0) ? -inf : round(tan(x * pi / 180.0) * 1e10) / 1e10 + 0.0)
+    // +0.0 to avoid -0.0
+    llvm::Constant *zero = llvm::ConstantFP::get(llvmCtx, llvm::APFloat(0.0));
+    llvm::Constant *full = llvm::ConstantFP::get(llvmCtx, llvm::APFloat(360.0));
+    llvm::Constant *posInf = llvm::ConstantFP::getInfinity(m_builder.getDoubleTy(), false);
+    llvm::Constant *negInf = llvm::ConstantFP::getInfinity(m_builder.getDoubleTy(), true);
+    llvm::Constant *undefined1 = llvm::ConstantFP::get(llvmCtx, llvm::APFloat(-270.0));
+    llvm::Constant *undefined2 = llvm::ConstantFP::get(llvmCtx, llvm::APFloat(90.0));
+    llvm::Constant *undefined3 = llvm::ConstantFP::get(llvmCtx, llvm::APFloat(-90.0));
+    llvm::Constant *undefined4 = llvm::ConstantFP::get(llvmCtx, llvm::APFloat(270.0));
+    llvm::Constant *pi = llvm::ConstantFP::get(llvmCtx, llvm::APFloat(std::acos(-1.0)));
+    llvm::Constant *piDeg = llvm::ConstantFP::get(llvmCtx, llvm::APFloat(180.0));
+    llvm::Constant *factor = llvm::ConstantFP::get(llvmCtx, llvm::APFloat(1e10));
+    llvm::Function *tanFunc = llvm::Intrinsic::getDeclaration(module, llvm::Intrinsic::tan, m_builder.getDoubleTy());
+    llvm::Function *roundFunc = llvm::Intrinsic::getDeclaration(module, llvm::Intrinsic::round, m_builder.getDoubleTy());
+    llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
+    llvm::Value *mod = m_builder.CreateFRem(num, full);
+    llvm::Value *isUndefined1 = m_builder.CreateFCmpOEQ(mod, undefined1);                                               // rem(x, 360.0) == -270.0
+    llvm::Value *isUndefined2 = m_builder.CreateFCmpOEQ(mod, undefined2);                                               // rem(x, 360.0) == 90.0
+    llvm::Value *isUndefined3 = m_builder.CreateFCmpOEQ(mod, undefined3);                                               // rem(x, 360.0) == -90.0
+    llvm::Value *isUndefined4 = m_builder.CreateFCmpOEQ(mod, undefined4);                                               // rem(x, 360.0) == 270.0
+    llvm::Value *tanResult = m_builder.CreateCall(tanFunc, m_builder.CreateFDiv(m_builder.CreateFMul(num, pi), piDeg)); // tan(x * pi / 180)
+    llvm::Value *rounded = m_builder.CreateCall(roundFunc, m_builder.CreateFMul(tanResult, factor));                    // round(tan(x * 180) * 1e10)
+    llvm::Value *result = m_builder.CreateFAdd(m_builder.CreateFDiv(rounded, factor), zero);                            // round(tan(x * pi / 180.0) * 1e10) / 1e10 + 0.0
+    llvm::Value *inner = m_builder.CreateSelect(m_builder.CreateOr(isUndefined3, isUndefined4), negInf, result);
+    ins->functionReturnReg->value = m_builder.CreateSelect(m_builder.CreateOr(isUndefined1, isUndefined2), posInf, inner);
+
+    return ins->next;
+}
+
+LLVMInstruction *Math::buildAsin(LLVMInstruction *ins)
+{
+    llvm::LLVMContext &llvmCtx = m_utils.llvmCtx();
+
+    assert(ins->args.size() == 1);
+    const auto &arg = ins->args[0];
+    // asin(x) * 180.0 / pi + 0.0
+    // +0.0 to avoid -0.0
+    llvm::Constant *zero = llvm::ConstantFP::get(llvmCtx, llvm::APFloat(0.0));
+    llvm::Constant *pi = llvm::ConstantFP::get(llvmCtx, llvm::APFloat(std::acos(-1.0)));
+    llvm::Constant *piDeg = llvm::ConstantFP::get(llvmCtx, llvm::APFloat(180.0));
+    llvm::Function *asinFunc = llvm::Intrinsic::getDeclaration(m_utils.module(), llvm::Intrinsic::asin, m_builder.getDoubleTy());
+    llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
+    ins->functionReturnReg->value = m_builder.CreateFAdd(m_builder.CreateFDiv(m_builder.CreateFMul(m_builder.CreateCall(asinFunc, num), piDeg), pi), zero);
+
+    return ins->next;
+}
+
+LLVMInstruction *Math::buildAcos(LLVMInstruction *ins)
+{
+    llvm::LLVMContext &llvmCtx = m_utils.llvmCtx();
+
+    assert(ins->args.size() == 1);
+    const auto &arg = ins->args[0];
+    // acos(x) * 180.0 / pi
+    llvm::Constant *pi = llvm::ConstantFP::get(llvmCtx, llvm::APFloat(std::acos(-1.0)));
+    llvm::Constant *piDeg = llvm::ConstantFP::get(llvmCtx, llvm::APFloat(180.0));
+    llvm::Function *acosFunc = llvm::Intrinsic::getDeclaration(m_utils.module(), llvm::Intrinsic::acos, m_builder.getDoubleTy());
+    llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
+    ins->functionReturnReg->value = m_builder.CreateFDiv(m_builder.CreateFMul(m_builder.CreateCall(acosFunc, num), piDeg), pi);
+
+    return ins->next;
+}
+
+LLVMInstruction *Math::buildAtan(LLVMInstruction *ins)
+{
+    llvm::LLVMContext &llvmCtx = m_utils.llvmCtx();
+
+    assert(ins->args.size() == 1);
+    const auto &arg = ins->args[0];
+    // atan(x) * 180.0 / pi
+    llvm::Constant *pi = llvm::ConstantFP::get(llvmCtx, llvm::APFloat(std::acos(-1.0)));
+    llvm::Constant *piDeg = llvm::ConstantFP::get(llvmCtx, llvm::APFloat(180.0));
+    llvm::Function *atanFunc = llvm::Intrinsic::getDeclaration(m_utils.module(), llvm::Intrinsic::atan, m_builder.getDoubleTy());
+    llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
+    ins->functionReturnReg->value = m_builder.CreateFDiv(m_builder.CreateFMul(m_builder.CreateCall(atanFunc, num), piDeg), pi);
+
+    return ins->next;
+}
+
+LLVMInstruction *Math::buildLn(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 1);
+    const auto &arg = ins->args[0];
+    // log(x)
+    llvm::Function *logFunc = llvm::Intrinsic::getDeclaration(m_utils.module(), llvm::Intrinsic::log, m_builder.getDoubleTy());
+    llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
+    ins->functionReturnReg->value = m_builder.CreateCall(logFunc, num);
+
+    return ins->next;
+}
+
+LLVMInstruction *Math::buildLog10(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 1);
+    const auto &arg = ins->args[0];
+    // log10(x)
+    llvm::Function *log10Func = llvm::Intrinsic::getDeclaration(m_utils.module(), llvm::Intrinsic::log10, m_builder.getDoubleTy());
+    llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
+    ins->functionReturnReg->value = m_builder.CreateCall(log10Func, num);
+
+    return ins->next;
+}
+
+LLVMInstruction *Math::buildExp(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 1);
+    const auto &arg = ins->args[0];
+    // exp(x)
+    llvm::Function *expFunc = llvm::Intrinsic::getDeclaration(m_utils.module(), llvm::Intrinsic::exp, m_builder.getDoubleTy());
+    llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
+    ins->functionReturnReg->value = m_builder.CreateCall(expFunc, num);
+
+    return ins->next;
+}
+
+LLVMInstruction *Math::buildExp10(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 1);
+    const auto &arg = ins->args[0];
+    // exp10(x)
+    llvm::Function *expFunc = llvm::Intrinsic::getDeclaration(m_utils.module(), llvm::Intrinsic::exp10, m_builder.getDoubleTy());
+    llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
+    ins->functionReturnReg->value = m_builder.CreateCall(expFunc, num);
+
+    return ins->next;
 }
diff --git a/src/engine/internal/llvm/instructions/math.h b/src/engine/internal/llvm/instructions/math.h
index a3bb36a5..c079e3b1 100644
--- a/src/engine/internal/llvm/instructions/math.h
+++ b/src/engine/internal/llvm/instructions/math.h
@@ -13,6 +13,30 @@ class Math : public InstructionGroup
         using InstructionGroup::InstructionGroup;
 
         ProcessResult process(LLVMInstruction *ins) override;
+
+    private:
+        LLVMInstruction *buildAdd(LLVMInstruction *ins);
+        LLVMInstruction *buildSub(LLVMInstruction *ins);
+        LLVMInstruction *buildMul(LLVMInstruction *ins);
+        LLVMInstruction *buildDiv(LLVMInstruction *ins);
+        LLVMInstruction *buildRandom(LLVMInstruction *ins);
+        LLVMInstruction *buildRandomInt(LLVMInstruction *ins);
+        LLVMInstruction *buildMod(LLVMInstruction *ins);
+        LLVMInstruction *buildRound(LLVMInstruction *ins);
+        LLVMInstruction *buildAbs(LLVMInstruction *ins);
+        LLVMInstruction *buildFloor(LLVMInstruction *ins);
+        LLVMInstruction *buildCeil(LLVMInstruction *ins);
+        LLVMInstruction *buildSqrt(LLVMInstruction *ins);
+        LLVMInstruction *buildSin(LLVMInstruction *ins);
+        LLVMInstruction *buildCos(LLVMInstruction *ins);
+        LLVMInstruction *buildTan(LLVMInstruction *ins);
+        LLVMInstruction *buildAsin(LLVMInstruction *ins);
+        LLVMInstruction *buildAcos(LLVMInstruction *ins);
+        LLVMInstruction *buildAtan(LLVMInstruction *ins);
+        LLVMInstruction *buildLn(LLVMInstruction *ins);
+        LLVMInstruction *buildLog10(LLVMInstruction *ins);
+        LLVMInstruction *buildExp(LLVMInstruction *ins);
+        LLVMInstruction *buildExp10(LLVMInstruction *ins);
 };
 
 } // namespace libscratchcpp::llvmins
diff --git a/src/engine/internal/llvm/instructions/procedures.cpp b/src/engine/internal/llvm/instructions/procedures.cpp
index 23fd3eb7..a6de4350 100644
--- a/src/engine/internal/llvm/instructions/procedures.cpp
+++ b/src/engine/internal/llvm/instructions/procedures.cpp
@@ -1,10 +1,96 @@
 // SPDX-License-Identifier: Apache-2.0
 
+#include <scratchcpp/blockprototype.h>
+
 #include "procedures.h"
+#include "../llvminstruction.h"
 #include "../llvmbuildutils.h"
+#include "../llvmcompilercontext.h"
 
+using namespace libscratchcpp;
 using namespace libscratchcpp::llvmins;
 
 ProcessResult Procedures::process(LLVMInstruction *ins)
 {
+    ProcessResult ret(true, ins);
+
+    switch (ins->type) {
+        case LLVMInstruction::Type::CallProcedure:
+            ret.next = buildCallProcedure(ins);
+            break;
+
+        case LLVMInstruction::Type::ProcedureArg:
+            ret.next = buildProcedureArg(ins);
+            break;
+
+        default:
+            ret.match = false;
+            break;
+    }
+
+    return ret;
+}
+
+LLVMInstruction *Procedures::buildCallProcedure(LLVMInstruction *ins)
+{
+    llvm::LLVMContext &llvmCtx = m_utils.llvmCtx();
+    llvm::Function *function = m_utils.function();
+
+    assert(ins->procedurePrototype);
+    assert(ins->args.size() == ins->procedurePrototype->argumentTypes().size());
+    m_utils.freeScopeHeap();
+    m_utils.syncVariables(m_utils.targetVariables());
+
+    std::string name = m_utils.scriptFunctionName(ins->procedurePrototype);
+    llvm::FunctionType *type = m_utils.scriptFunctionType(ins->procedurePrototype);
+    std::vector<llvm::Value *> args;
+
+    llvm::FunctionType *funcType = m_utils.scriptFunctionType(nullptr);
+    int passArgCount = funcType->getNumParams();
+
+    for (size_t i = 0; i < passArgCount; i++)
+        args.push_back(function->getArg(i));
+
+    // Add warp arg
+    if (m_utils.warp())
+        args.push_back(m_builder.getInt1(true));
+    else
+        args.push_back(m_utils.procedurePrototype() ? m_utils.warpArg() : m_builder.getInt1(false));
+
+    // Add procedure args
+    for (const auto &arg : ins->args) {
+        if (arg.first == Compiler::StaticType::Unknown)
+            args.push_back(m_utils.createValue(arg.second));
+        else
+            args.push_back(m_utils.castValue(arg.second, arg.first));
+    }
+
+    llvm::Value *handle = m_builder.CreateCall(m_utils.functions().resolveFunction(name, type), args);
+
+    if (!m_utils.warp() && !ins->procedurePrototype->warp()) {
+        llvm::BasicBlock *suspendBranch = llvm::BasicBlock::Create(llvmCtx, "", function);
+        llvm::BasicBlock *nextBranch = llvm::BasicBlock::Create(llvmCtx, "", function);
+        m_builder.CreateCondBr(m_builder.CreateIsNull(handle), nextBranch, suspendBranch);
+
+        m_builder.SetInsertPoint(suspendBranch);
+        m_utils.createSuspend();
+        llvm::Value *done = m_builder.CreateCall(m_utils.compilerCtx()->coroutineResumeFunction(), { handle });
+        m_builder.CreateCondBr(done, nextBranch, suspendBranch);
+
+        m_builder.SetInsertPoint(nextBranch);
+    }
+
+    m_utils.reloadVariables(m_utils.targetVariables());
+    return ins->next;
+}
+
+LLVMInstruction *Procedures::buildProcedureArg(LLVMInstruction *ins)
+{
+    assert(m_utils.procedurePrototype());
+    llvm::FunctionType *funcType = m_utils.scriptFunctionType(nullptr);
+    int passArgCount = funcType->getNumParams();
+    llvm::Value *arg = m_utils.function()->getArg(passArgCount + 1 + ins->procedureArgIndex); // omit warp arg
+    ins->functionReturnReg->value = arg;
+
+    return ins->next;
 }
diff --git a/src/engine/internal/llvm/instructions/procedures.h b/src/engine/internal/llvm/instructions/procedures.h
index f677bff7..281277ac 100644
--- a/src/engine/internal/llvm/instructions/procedures.h
+++ b/src/engine/internal/llvm/instructions/procedures.h
@@ -13,6 +13,10 @@ class Procedures : public InstructionGroup
         using InstructionGroup::InstructionGroup;
 
         ProcessResult process(LLVMInstruction *ins) override;
+
+    private:
+        LLVMInstruction *buildCallProcedure(LLVMInstruction *ins);
+        LLVMInstruction *buildProcedureArg(LLVMInstruction *ins);
 };
 
 } // namespace libscratchcpp::llvmins
diff --git a/src/engine/internal/llvm/instructions/string.cpp b/src/engine/internal/llvm/instructions/string.cpp
index 93b19610..c973196b 100644
--- a/src/engine/internal/llvm/instructions/string.cpp
+++ b/src/engine/internal/llvm/instructions/string.cpp
@@ -1,10 +1,136 @@
 // SPDX-License-Identifier: Apache-2.0
 
 #include "string.h"
+#include "../llvminstruction.h"
 #include "../llvmbuildutils.h"
+#include "../llvmcompilercontext.h"
 
+using namespace libscratchcpp;
 using namespace libscratchcpp::llvmins;
 
 ProcessResult String::process(LLVMInstruction *ins)
 {
+    ProcessResult ret(true, ins);
+
+    switch (ins->type) {
+        case LLVMInstruction::Type::StringConcat:
+            ret.next = buildStringConcat(ins);
+            break;
+
+        case LLVMInstruction::Type::StringChar:
+            ret.next = buildStringChar(ins);
+            break;
+
+        case LLVMInstruction::Type::StringLength:
+            ret.next = buildStringLength(ins);
+            break;
+
+        default:
+            ret.match = false;
+            break;
+    }
+
+    return ret;
+}
+
+LLVMInstruction *String::buildStringConcat(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 2);
+    const auto &arg1 = ins->args[0];
+    const auto &arg2 = ins->args[1];
+    llvm::Value *str1 = m_utils.castValue(arg1.second, arg1.first);
+    llvm::Value *str2 = m_utils.castValue(arg2.second, arg2.first);
+    llvm::PointerType *charPointerType = m_builder.getInt16Ty()->getPointerTo();
+    llvm::StructType *stringPtrType = m_utils.compilerCtx()->stringPtrType();
+    llvm::Function *memcpyFunc = llvm::Intrinsic::getDeclaration(m_utils.module(), llvm::Intrinsic::memcpy_inline, { charPointerType, charPointerType, m_builder.getInt64Ty() });
+
+    // StringPtr *result = string_pool_new(true)
+    llvm::Value *result = m_builder.CreateCall(m_utils.functions().resolve_string_pool_new(), m_builder.getInt1(true));
+    m_utils.freeStringLater(result);
+
+    // result->size = string1->size + string2->size
+    llvm::Value *sizeField1 = m_builder.CreateStructGEP(stringPtrType, str1, 1);
+    llvm::Value *sizeField2 = m_builder.CreateStructGEP(stringPtrType, str2, 1);
+    llvm::Value *size1 = m_builder.CreateLoad(m_builder.getInt64Ty(), sizeField1);
+    llvm::Value *size2 = m_builder.CreateLoad(m_builder.getInt64Ty(), sizeField2);
+    llvm::Value *resultSize = m_builder.CreateAdd(size1, size2);
+    llvm::Value *resultSizeField = m_builder.CreateStructGEP(stringPtrType, result, 1);
+    m_builder.CreateStore(resultSize, resultSizeField);
+
+    // string_alloc(result, result->size)
+    m_builder.CreateCall(m_utils.functions().resolve_string_alloc(), { result, resultSize });
+
+    // memcpy(result->data, string1->data, string1->size * sizeof(char16_t))
+    llvm::Value *dataField1 = m_builder.CreateStructGEP(stringPtrType, str1, 0);
+    llvm::Value *data1 = m_builder.CreateLoad(charPointerType, dataField1);
+    llvm::Value *resultDataField = m_builder.CreateStructGEP(stringPtrType, result, 0);
+    llvm::Value *writePtr = m_builder.CreateLoad(charPointerType, resultDataField);
+    m_builder.CreateCall(memcpyFunc, { writePtr, data1, m_builder.CreateMul(size1, m_builder.getInt64(2)), m_builder.getInt1(false) });
+
+    // memcpy(result->data + string1->size, string2->data, (string2->size + 1) * sizeof(char16_t))
+    // +1: null-terminate
+    llvm::Value *dataField2 = m_builder.CreateStructGEP(stringPtrType, str2, 0);
+    llvm::Value *data2 = m_builder.CreateLoad(charPointerType, dataField2);
+    writePtr = m_builder.CreateGEP(m_builder.getInt16Ty(), writePtr, size1);
+    m_builder.CreateCall(memcpyFunc, { writePtr, data2, m_builder.CreateMul(m_builder.CreateAdd(size2, m_builder.getInt64(1)), m_builder.getInt64(2)), m_builder.getInt1(false) });
+
+    ins->functionReturnReg->value = result;
+
+    return ins->next;
+}
+
+LLVMInstruction *String::buildStringChar(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 2);
+    const auto &arg1 = ins->args[0];
+    const auto &arg2 = ins->args[1];
+    llvm::Value *str = m_utils.castValue(arg1.second, arg1.first);
+    llvm::Value *index = m_builder.CreateFPToSI(m_utils.castValue(arg2.second, arg2.first), m_builder.getInt64Ty());
+    llvm::PointerType *charPointerType = m_builder.getInt16Ty()->getPointerTo();
+    llvm::StructType *stringPtrType = m_utils.compilerCtx()->stringPtrType();
+
+    // Get data ptr and size
+    llvm::Value *dataField = m_builder.CreateStructGEP(stringPtrType, str, 0);
+    llvm::Value *data = m_builder.CreateLoad(charPointerType, dataField);
+    llvm::Value *sizeField = m_builder.CreateStructGEP(stringPtrType, str, 1);
+    llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), sizeField);
+
+    // Check range, get character ptr
+    llvm::Value *inRange = m_builder.CreateAnd(m_builder.CreateICmpSGE(index, m_builder.getInt64(0)), m_builder.CreateICmpSLT(index, size));
+    llvm::Value *charPtr = m_builder.CreateGEP(m_builder.getInt16Ty(), data, index);
+
+    // Allocate string
+    llvm::Value *result = m_builder.CreateCall(m_utils.functions().resolve_string_pool_new(), m_builder.getInt1(true));
+    m_utils.freeStringLater(result);
+    m_builder.CreateCall(m_utils.functions().resolve_string_alloc(), { result, m_builder.getInt64(1) }); // size 1 to avoid branching
+
+    // Get result data ptr
+    dataField = m_builder.CreateStructGEP(stringPtrType, result, 0);
+    data = m_builder.CreateLoad(charPointerType, dataField);
+
+    // Write result
+    llvm::Value *char1 = m_builder.CreateGEP(m_builder.getInt16Ty(), data, m_builder.getInt64(0));
+    llvm::Value *char2 = m_builder.CreateGEP(m_builder.getInt16Ty(), data, m_builder.getInt64(1));
+    sizeField = m_builder.CreateStructGEP(stringPtrType, result, 1);
+    m_builder.CreateStore(m_builder.CreateSelect(inRange, m_builder.CreateLoad(m_builder.getInt16Ty(), charPtr), m_builder.getInt16(0)), char1);
+    m_builder.CreateStore(m_builder.getInt16(0), char2);
+    m_builder.CreateStore(m_builder.CreateSelect(inRange, m_builder.getInt64(1), m_builder.getInt64(0)), sizeField);
+
+    ins->functionReturnReg->value = result;
+
+    return ins->next;
+}
+
+LLVMInstruction *String::buildStringLength(LLVMInstruction *ins)
+{
+    llvm::StructType *stringPtrType = m_utils.compilerCtx()->stringPtrType();
+
+    assert(ins->args.size() == 1);
+    const auto &arg = ins->args[0];
+    llvm::Value *str = m_utils.castValue(arg.second, arg.first);
+    llvm::Value *sizeField = m_builder.CreateStructGEP(stringPtrType, str, 1);
+    llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), sizeField);
+    ins->functionReturnReg->value = m_builder.CreateSIToFP(size, m_builder.getDoubleTy());
+
+    return ins->next;
 }
diff --git a/src/engine/internal/llvm/instructions/string.h b/src/engine/internal/llvm/instructions/string.h
index 892d8287..3558471d 100644
--- a/src/engine/internal/llvm/instructions/string.h
+++ b/src/engine/internal/llvm/instructions/string.h
@@ -13,6 +13,11 @@ class String : public InstructionGroup
         using InstructionGroup::InstructionGroup;
 
         ProcessResult process(LLVMInstruction *ins) override;
+
+    private:
+        LLVMInstruction *buildStringConcat(LLVMInstruction *ins);
+        LLVMInstruction *buildStringChar(LLVMInstruction *ins);
+        LLVMInstruction *buildStringLength(LLVMInstruction *ins);
 };
 
 } // namespace libscratchcpp::llvmins
diff --git a/src/engine/internal/llvm/instructions/variables.cpp b/src/engine/internal/llvm/instructions/variables.cpp
index 94559cad..204fee06 100644
--- a/src/engine/internal/llvm/instructions/variables.cpp
+++ b/src/engine/internal/llvm/instructions/variables.cpp
@@ -1,10 +1,158 @@
 // SPDX-License-Identifier: Apache-2.0
 
 #include "variables.h"
+#include "../llvminstruction.h"
 #include "../llvmbuildutils.h"
 
+using namespace libscratchcpp;
 using namespace libscratchcpp::llvmins;
 
 ProcessResult Variables::process(LLVMInstruction *ins)
 {
+    ProcessResult ret(true, ins);
+
+    switch (ins->type) {
+        case LLVMInstruction::Type::CreateLocalVariable:
+            ret.next = buildCreateLocalVariable(ins);
+            break;
+
+        case LLVMInstruction::Type::WriteLocalVariable:
+            ret.next = buildWriteLocalVariable(ins);
+            break;
+
+        case LLVMInstruction::Type::ReadLocalVariable:
+            ret.next = buildReadLocalVariable(ins);
+            break;
+
+        case LLVMInstruction::Type::WriteVariable:
+            ret.next = buildWriteVariable(ins);
+            break;
+
+        case LLVMInstruction::Type::ReadVariable:
+            ret.next = buildReadVariable(ins);
+            break;
+
+        default:
+            ret.match = false;
+            break;
+    }
+
+    return ret;
+}
+
+LLVMInstruction *Variables::buildCreateLocalVariable(LLVMInstruction *ins)
+{
+    assert(ins->args.empty());
+    llvm::Type *type = nullptr;
+
+    switch (ins->functionReturnReg->type()) {
+        case Compiler::StaticType::Number:
+            type = m_builder.getDoubleTy();
+            break;
+
+        case Compiler::StaticType::Bool:
+            type = m_builder.getInt1Ty();
+            break;
+
+        case Compiler::StaticType::String:
+            std::cerr << "error: local variables do not support string type" << std::endl;
+            break;
+
+        case Compiler::StaticType::Pointer:
+            std::cerr << "error: local variables do not support pointer type" << std::endl;
+            break;
+
+        default:
+            assert(false);
+            break;
+    }
+
+    ins->functionReturnReg->value = m_utils.addAlloca(type);
+    return ins->next;
+}
+
+LLVMInstruction *Variables::buildWriteLocalVariable(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 2);
+    const auto &arg1 = ins->args[0];
+    const auto &arg2 = ins->args[1];
+    llvm::Value *converted = m_utils.castValue(arg2.second, arg2.first);
+    m_builder.CreateStore(converted, arg1.second->value);
+    return ins->next;
+}
+
+LLVMInstruction *Variables::buildReadLocalVariable(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 1);
+    const auto &arg = ins->args[0];
+    llvm::Type *type = nullptr;
+
+    switch (ins->functionReturnReg->type()) {
+        case Compiler::StaticType::Number:
+            type = m_builder.getDoubleTy();
+            break;
+
+        case Compiler::StaticType::Bool:
+            type = m_builder.getInt1Ty();
+            break;
+
+        default:
+            assert(false);
+            break;
+    }
+
+    ins->functionReturnReg->value = m_builder.CreateLoad(type, arg.second->value);
+    return ins->next;
+}
+
+LLVMInstruction *Variables::buildWriteVariable(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 1);
+    const auto &arg = ins->args[0];
+    Compiler::StaticType argType = m_utils.optimizeRegisterType(arg.second);
+    LLVMVariablePtr &varPtr = m_utils.variablePtr(ins->workVariable);
+    varPtr.changed = true; // TODO: Handle loops and if statements
+
+    Compiler::StaticType varType = Compiler::StaticType::Unknown;
+
+    if (m_utils.warp())
+        varType = m_utils.typeAnalyzer().variableType(ins->workVariable, ins, Compiler::StaticType::Unknown);
+
+    // Initialize stack variable on first assignment
+    // TODO: Use stack in the top level (outside loops and if statements)
+    /*if (!varPtr.onStack) {
+        varPtr.onStack = true;
+        varPtr.type = type; // don't care about unknown type on first assignment
+
+                      ValueType mappedType;
+
+                        if (type == Compiler::StaticType::String || type == Compiler::StaticType::Unknown) {
+                            // Value functions are used for these types, so don't break them
+                            mappedType = ValueType::Number;
+                        } else {
+                            auto it = std::find_if(TYPE_MAP.begin(), TYPE_MAP.end(), [type](const std::pair<ValueType, Compiler::StaticType> &pair) { return pair.second == type; });
+                            assert(it != TYPE_MAP.cend());
+                            mappedType = it->first;
+                        }
+
+                        llvm::Value *typeField = m_builder.CreateStructGEP(m_valueDataType, varPtr.stackPtr, 1);
+                        m_builder.CreateStore(m_builder.getInt32(static_cast<uint32_t>(mappedType)), typeField);
+                    }*/
+
+    m_utils.createValueStore(arg.second, varPtr.stackPtr, argType, varType);
+    return ins->next;
+}
+
+LLVMInstruction *Variables::buildReadVariable(LLVMInstruction *ins)
+{
+    assert(ins->args.size() == 0);
+    LLVMVariablePtr &varPtr = m_utils.variablePtr(ins->workVariable);
+    Compiler::StaticType type = Compiler::StaticType::Unknown;
+
+    if (m_utils.warp())
+        type = m_utils.typeAnalyzer().variableType(ins->workVariable, ins, Compiler::StaticType::Unknown);
+
+    ins->functionReturnReg->value = varPtr.onStack && !(ins->loopCondition && !m_utils.warp()) ? varPtr.stackPtr : varPtr.heapPtr;
+    ins->functionReturnReg->setType(type);
+    return ins->next;
 }
diff --git a/src/engine/internal/llvm/instructions/variables.h b/src/engine/internal/llvm/instructions/variables.h
index 26f5110c..77c44193 100644
--- a/src/engine/internal/llvm/instructions/variables.h
+++ b/src/engine/internal/llvm/instructions/variables.h
@@ -13,6 +13,13 @@ class Variables : public InstructionGroup
         using InstructionGroup::InstructionGroup;
 
         ProcessResult process(LLVMInstruction *ins) override;
+
+    private:
+        LLVMInstruction *buildCreateLocalVariable(LLVMInstruction *ins);
+        LLVMInstruction *buildWriteLocalVariable(LLVMInstruction *ins);
+        LLVMInstruction *buildReadLocalVariable(LLVMInstruction *ins);
+        LLVMInstruction *buildWriteVariable(LLVMInstruction *ins);
+        LLVMInstruction *buildReadVariable(LLVMInstruction *ins);
 };
 
 } // namespace libscratchcpp::llvmins
diff --git a/src/engine/internal/llvm/llvmbuildutils.cpp b/src/engine/internal/llvm/llvmbuildutils.cpp
index e8116529..d1b78ece 100644
--- a/src/engine/internal/llvm/llvmbuildutils.cpp
+++ b/src/engine/internal/llvm/llvmbuildutils.cpp
@@ -3,11 +3,14 @@
 #include <scratchcpp/target.h>
 #include <scratchcpp/variable.h>
 #include <scratchcpp/list.h>
+#include <scratchcpp/blockprototype.h>
+#include <scratchcpp/compiler.h>
 
 #include "llvmbuildutils.h"
 #include "llvmfunctions.h"
 #include "llvmcompilercontext.h"
 #include "llvmregister.h"
+#include "llvminstruction.h"
 
 using namespace libscratchcpp;
 
@@ -18,12 +21,13 @@ static std::unordered_map<ValueType, Compiler::StaticType> TYPE_MAP = {
     { ValueType::Pointer, Compiler::StaticType::Pointer }
 };
 
-LLVMBuildUtils::LLVMBuildUtils(LLVMCompilerContext *ctx, llvm::IRBuilder<> &builder) :
+LLVMBuildUtils::LLVMBuildUtils(LLVMCompilerContext *ctx, llvm::IRBuilder<> &builder, Compiler::CodeType codeType) :
     m_ctx(ctx),
     m_llvmCtx(*ctx->llvmCtx()),
     m_builder(builder),
     m_functions(ctx, &builder),
-    m_target(ctx->target())
+    m_target(ctx->target()),
+    m_codeType(codeType)
 {
     initTypes();
     createVariableMap();
@@ -34,6 +38,7 @@ void LLVMBuildUtils::init(llvm::Function *function, BlockPrototype *procedurePro
 {
     m_function = function;
     m_procedurePrototype = procedurePrototype;
+    m_warp = warp;
 
     m_executionContextPtr = m_function->getArg(0);
     m_targetPtr = m_function->getArg(1);
@@ -47,6 +52,10 @@ void LLVMBuildUtils::init(llvm::Function *function, BlockPrototype *procedurePro
     m_stringHeap.clear();
     pushScopeLevel();
 
+    // Init coroutine
+    if (!m_warp)
+        m_coroutine = std::make_unique<LLVMCoroutine>(m_ctx->module(), &m_builder, m_function);
+
     // Create variable pointers
     for (auto &[var, varPtr] : m_variablePtrs) {
         llvm::Value *ptr = getVariablePtr(m_targetVariables, var);
@@ -86,12 +95,51 @@ void LLVMBuildUtils::init(llvm::Function *function, BlockPrototype *procedurePro
         listPtr.sizePtr = m_builder.CreateCall(m_functions.resolve_list_size_ptr(), listPtr.ptr);
         listPtr.allocatedSizePtr = m_builder.CreateCall(m_functions.resolve_list_alloc_size_ptr(), listPtr.ptr);
     }
+
+    // Create end branch
+    m_endBranch = llvm::BasicBlock::Create(m_llvmCtx, "end", m_function);
 }
 
-void LLVMBuildUtils::end()
+void LLVMBuildUtils::end(LLVMInstruction *lastInstruction, LLVMRegister *lastConstant)
 {
     assert(m_stringHeap.size() == 1);
     freeScopeHeap();
+
+    m_builder.CreateBr(m_endBranch);
+
+    m_builder.SetInsertPoint(m_endBranch);
+    syncVariables(m_targetVariables);
+
+    // End the script function
+    llvm::PointerType *pointerType = llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0);
+
+    switch (m_codeType) {
+        case Compiler::CodeType::Script:
+            if (m_warp)
+                m_builder.CreateRet(llvm::ConstantPointerNull::get(pointerType));
+            else
+                m_coroutine->end();
+            break;
+
+        case Compiler::CodeType::Reporter: {
+            // Use last instruction return value (or last constant) and create a ValueData instance
+            assert(lastInstruction || lastConstant);
+            LLVMRegister *ret = lastInstruction ? lastInstruction->functionReturnReg : lastConstant;
+            llvm::Value *copy = createNewValue(ret);
+            m_builder.CreateRet(m_builder.CreateLoad(m_valueDataType, copy));
+            break;
+        }
+
+        case Compiler::CodeType::HatPredicate:
+            // Use last instruction return value (or last constant)
+            assert(lastInstruction || lastConstant);
+
+            if (lastInstruction)
+                m_builder.CreateRet(castValue(lastInstruction->functionReturnReg, Compiler::StaticType::Bool));
+            else
+                m_builder.CreateRet(castValue(lastConstant, Compiler::StaticType::Bool));
+            break;
+    }
 }
 
 LLVMCompilerContext *LLVMBuildUtils::compilerCtx() const
@@ -129,6 +177,71 @@ LLVMTypeAnalyzer &LLVMBuildUtils::typeAnalyzer()
     return m_typeAnalyzer;
 }
 
+std::string LLVMBuildUtils::scriptFunctionName(BlockPrototype *procedurePrototype)
+{
+    std::string name;
+
+    switch (m_codeType) {
+        case Compiler::CodeType::Script:
+            name = "script";
+            break;
+
+        case Compiler::CodeType::Reporter:
+            name = "reporter";
+            break;
+
+        case Compiler::CodeType::HatPredicate:
+            name = "predicate";
+            break;
+    }
+
+    return procedurePrototype ? "proc." + procedurePrototype->procCode() : name;
+}
+
+llvm::FunctionType *LLVMBuildUtils::scriptFunctionType(BlockPrototype *procedurePrototype)
+{
+    // void *f(ExecutionContext *, Target *, ValueData **, List **, (warp arg), (procedure args...))
+    // ValueData f(...) (reporters)
+    // bool f(...) (hat predicates)
+    llvm::Type *pointerType = llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0);
+    std::vector<llvm::Type *> argTypes = { pointerType, pointerType, pointerType, pointerType };
+
+    if (procedurePrototype) {
+        argTypes.push_back(m_builder.getInt1Ty()); // warp arg (only in procedures)
+        const auto &types = procedurePrototype->argumentTypes();
+
+        for (BlockPrototype::ArgType type : types) {
+            if (type == BlockPrototype::ArgType::Bool)
+                argTypes.push_back(m_builder.getInt1Ty());
+            else
+                argTypes.push_back(m_valueDataType->getPointerTo());
+        }
+    }
+
+    llvm::Type *retType = nullptr;
+
+    switch (m_codeType) {
+        case Compiler::CodeType::Script:
+            retType = pointerType;
+            break;
+
+        case Compiler::CodeType::Reporter:
+            retType = m_valueDataType;
+            break;
+
+        case Compiler::CodeType::HatPredicate:
+            retType = m_builder.getInt1Ty();
+            break;
+    }
+
+    return llvm::FunctionType::get(retType, argTypes, false);
+}
+
+llvm::BasicBlock *LLVMBuildUtils::endBranch() const
+{
+    return m_endBranch;
+}
+
 BlockPrototype *LLVMBuildUtils::procedurePrototype() const
 {
     return m_procedurePrototype;
@@ -164,6 +277,11 @@ llvm::Value *LLVMBuildUtils::warpArg()
     return m_warpArg;
 }
 
+LLVMCoroutine *LLVMBuildUtils::coroutine() const
+{
+    return m_coroutine.get();
+}
+
 void LLVMBuildUtils::createVariablePtr(Variable *variable)
 {
     if (m_variablePtrs.find(variable) == m_variablePtrs.cend())
@@ -243,6 +361,16 @@ void LLVMBuildUtils::freeScopeHeap()
     heap.clear();
 }
 
+std::vector<LLVMIfStatement> &LLVMBuildUtils::ifStatements()
+{
+    return m_ifStatements;
+}
+
+std::vector<LLVMLoop> &LLVMBuildUtils::loops()
+{
+    return m_loops;
+}
+
 Compiler::StaticType LLVMBuildUtils::optimizeRegisterType(LLVMRegister *reg)
 {
     Compiler::StaticType ret = reg->type();
@@ -842,6 +970,30 @@ llvm::Value *LLVMBuildUtils::createStringComparison(LLVMRegister *arg1, LLVMRegi
     }
 }
 
+void LLVMBuildUtils::createSuspend()
+{
+    if (m_coroutine) {
+        assert(!m_warp);
+        llvm::BasicBlock *suspendBranch, *nextBranch;
+
+        if (m_warpArg) {
+            suspendBranch = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
+            nextBranch = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
+            m_builder.CreateCondBr(m_warpArg, nextBranch, suspendBranch);
+            m_builder.SetInsertPoint(suspendBranch);
+        }
+
+        syncVariables(m_targetVariables);
+        m_coroutine->createSuspend();
+        reloadVariables(m_targetVariables);
+
+        if (m_warpArg) {
+            m_builder.CreateBr(nextBranch);
+            m_builder.SetInsertPoint(nextBranch);
+        }
+    }
+}
+
 void LLVMBuildUtils::initTypes()
 {
     m_valueDataType = m_ctx->valueDataType();
diff --git a/src/engine/internal/llvm/llvmbuildutils.h b/src/engine/internal/llvm/llvmbuildutils.h
index 0d7d593e..9ca28a1e 100644
--- a/src/engine/internal/llvm/llvmbuildutils.h
+++ b/src/engine/internal/llvm/llvmbuildutils.h
@@ -8,11 +8,15 @@
 #include "llvmvariableptr.h"
 #include "llvmlistptr.h"
 #include "llvmtypeanalyzer.h"
+#include "llvmcoroutine.h"
+#include "llvmifstatement.h"
+#include "llvmloop.h"
 
 namespace libscratchcpp
 {
 
 class LLVMRegister;
+class LLVMCoroutine;
 
 class LLVMBuildUtils
 {
@@ -24,10 +28,10 @@ class LLVMBuildUtils
             LT
         };
 
-        LLVMBuildUtils(LLVMCompilerContext *ctx, llvm::IRBuilder<> &builder);
+        LLVMBuildUtils(LLVMCompilerContext *ctx, llvm::IRBuilder<> &builder, Compiler::CodeType codeType);
 
         void init(llvm::Function *function, BlockPrototype *procedurePrototype, bool warp);
-        void end();
+        void end(LLVMInstruction *lastInstruction, LLVMRegister *lastConstant);
 
         LLVMCompilerContext *compilerCtx() const;
         llvm::LLVMContext &llvmCtx();
@@ -37,6 +41,11 @@ class LLVMBuildUtils
         LLVMFunctions &functions();
         LLVMTypeAnalyzer &typeAnalyzer();
 
+        std::string scriptFunctionName(BlockPrototype *procedurePrototype);
+        llvm::FunctionType *scriptFunctionType(BlockPrototype *procedurePrototype);
+
+        llvm::BasicBlock *endBranch() const;
+
         BlockPrototype *procedurePrototype() const;
         bool warp() const;
 
@@ -46,6 +55,8 @@ class LLVMBuildUtils
         llvm::Value *targetLists();
         llvm::Value *warpArg();
 
+        LLVMCoroutine *coroutine() const;
+
         void createVariablePtr(Variable *variable);
         void createListPtr(List *list);
 
@@ -61,6 +72,9 @@ class LLVMBuildUtils
         void freeStringLater(llvm::Value *value);
         void freeScopeHeap();
 
+        std::vector<LLVMIfStatement> &ifStatements();
+        std::vector<LLVMLoop> &loops();
+
         static Compiler::StaticType optimizeRegisterType(LLVMRegister *reg);
         static Compiler::StaticType mapType(ValueType type);
 
@@ -80,6 +94,8 @@ class LLVMBuildUtils
         llvm::Value *createComparison(LLVMRegister *arg1, LLVMRegister *arg2, Comparison type);
         llvm::Value *createStringComparison(LLVMRegister *arg1, LLVMRegister *arg2, bool caseSensitive);
 
+        void createSuspend();
+
     private:
         void initTypes();
         void createVariableMap();
@@ -103,11 +119,14 @@ class LLVMBuildUtils
         Target *m_target = nullptr;
         llvm::Function *m_function = nullptr;
 
+        llvm::BasicBlock *m_endBranch = nullptr;
+
         llvm::StructType *m_valueDataType = nullptr;
         llvm::StructType *m_stringPtrType = nullptr;
 
         BlockPrototype *m_procedurePrototype = nullptr;
         bool m_warp = false;
+        Compiler::CodeType m_codeType = Compiler::CodeType::Script;
 
         llvm::Value *m_executionContextPtr = nullptr;
         llvm::Value *m_targetPtr = nullptr;
@@ -115,6 +134,8 @@ class LLVMBuildUtils
         llvm::Value *m_targetLists = nullptr;
         llvm::Value *m_warpArg = nullptr;
 
+        std::unique_ptr<LLVMCoroutine> m_coroutine;
+
         std::unordered_map<Variable *, size_t> m_targetVariableMap;
         std::unordered_map<Variable *, LLVMVariablePtr> m_variablePtrs;
 
@@ -122,6 +143,9 @@ class LLVMBuildUtils
         std::unordered_map<List *, LLVMListPtr> m_listPtrs;
 
         std::vector<std::vector<llvm::Value *>> m_stringHeap; // scopes
+
+        std::vector<LLVMIfStatement> m_ifStatements;
+        std::vector<LLVMLoop> m_loops;
 };
 
 } // namespace libscratchcpp
diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp
index 6cdd2d62..d1481de8 100644
--- a/src/engine/internal/llvm/llvmcodebuilder.cpp
+++ b/src/engine/internal/llvm/llvmcodebuilder.cpp
@@ -27,16 +27,14 @@ LLVMCodeBuilder::LLVMCodeBuilder(LLVMCompilerContext *ctx, BlockPrototype *proce
     m_llvmCtx(*ctx->llvmCtx()),
     m_module(ctx->module()),
     m_builder(m_llvmCtx),
-    m_utils(ctx, m_builder),
+    m_utils(ctx, m_builder, codeType),
     m_procedurePrototype(procedurePrototype),
     m_defaultWarp(procedurePrototype ? procedurePrototype->warp() : false),
     m_warp(m_defaultWarp),
-    m_codeType(codeType)
+    m_codeType(codeType),
+    m_instructionBuilder(m_utils)
 {
     initTypes();
-
-    llvm::FunctionType *funcType = getMainFunctionType(nullptr);
-    m_defaultArgCount = funcType->getNumParams();
 }
 
 std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
@@ -63,8 +61,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
     m_builder.setFastMathFlags(fmf);
 
     // Create function
-    std::string funcName = getMainFunctionName(m_procedurePrototype);
-    llvm::FunctionType *funcType = getMainFunctionType(m_procedurePrototype);
+    std::string funcName = m_utils.scriptFunctionName(m_procedurePrototype);
+    llvm::FunctionType *funcType = m_utils.scriptFunctionType(m_procedurePrototype);
 
     if (m_procedurePrototype)
         m_function = getOrCreateFunction(funcName, funcType);
@@ -72,1296 +70,17 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
         m_function = llvm::Function::Create(funcType, llvm::Function::ExternalLinkage, funcName, m_module);
 
     llvm::BasicBlock *entry = llvm::BasicBlock::Create(m_llvmCtx, "entry", m_function);
-    llvm::BasicBlock *endBranch = llvm::BasicBlock::Create(m_llvmCtx, "end", m_function);
     m_builder.SetInsertPoint(entry);
 
-    // Init coroutine
-    std::unique_ptr<LLVMCoroutine> coro;
-
-    if (!m_warp)
-        coro = std::make_unique<LLVMCoroutine>(m_module, &m_builder, m_function);
-
-    std::vector<LLVMIfStatement> ifStatements;
-    std::vector<LLVMLoop> loops;
-
     m_utils.init(m_function, m_procedurePrototype, m_warp);
 
-    // Execute recorded instructions
+    // Build recorded instructions
     LLVMInstruction *ins = m_instructions.first();
 
-    while (ins) {
-        switch (ins->type) {
-            case LLVMInstruction::Type::FunctionCall: {
-                std::vector<llvm::Type *> types;
-                std::vector<llvm::Value *> args;
-
-                // Variables must be synchronized because the function can read them
-                m_utils.syncVariables(m_utils.targetVariables());
-
-                // Add execution context arg
-                if (ins->functionCtxArg) {
-                    types.push_back(llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0));
-                    args.push_back(m_utils.executionContextPtr());
-                }
-
-                // Add target pointer arg
-                if (ins->functionTargetArg) {
-                    types.push_back(llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0));
-                    args.push_back(m_utils.targetPtr());
-                }
-
-                // Args
-                for (auto &arg : ins->args) {
-                    types.push_back(m_utils.getType(arg.first));
-                    args.push_back(m_utils.castValue(arg.second, arg.first));
-                }
-
-                llvm::Type *retType = m_utils.getType(ins->functionReturnReg ? ins->functionReturnReg->type() : Compiler::StaticType::Void);
-                llvm::Value *ret = m_builder.CreateCall(m_utils.functions().resolveFunction(ins->functionName, llvm::FunctionType::get(retType, types, false)), args);
-
-                if (ins->functionReturnReg) {
-                    ins->functionReturnReg->value = ret;
-
-                    if (ins->functionReturnReg->type() == Compiler::StaticType::String)
-                        m_utils.freeStringLater(ins->functionReturnReg->value);
-                }
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::Add: {
-                assert(ins->args.size() == 2);
-                const auto &arg1 = ins->args[0];
-                const auto &arg2 = ins->args[1];
-                llvm::Value *num1 = m_utils.removeNaN(m_utils.castValue(arg1.second, arg1.first));
-                llvm::Value *num2 = m_utils.removeNaN(m_utils.castValue(arg2.second, arg2.first));
-                ins->functionReturnReg->value = m_builder.CreateFAdd(num1, num2);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::Sub: {
-                assert(ins->args.size() == 2);
-                const auto &arg1 = ins->args[0];
-                const auto &arg2 = ins->args[1];
-                llvm::Value *num1 = m_utils.removeNaN(m_utils.castValue(arg1.second, arg1.first));
-                llvm::Value *num2 = m_utils.removeNaN(m_utils.castValue(arg2.second, arg2.first));
-                ins->functionReturnReg->value = m_builder.CreateFSub(num1, num2);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::Mul: {
-                assert(ins->args.size() == 2);
-                const auto &arg1 = ins->args[0];
-                const auto &arg2 = ins->args[1];
-                llvm::Value *num1 = m_utils.removeNaN(m_utils.castValue(arg1.second, arg1.first));
-                llvm::Value *num2 = m_utils.removeNaN(m_utils.castValue(arg2.second, arg2.first));
-                ins->functionReturnReg->value = m_builder.CreateFMul(num1, num2);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::Div: {
-                assert(ins->args.size() == 2);
-                const auto &arg1 = ins->args[0];
-                const auto &arg2 = ins->args[1];
-                llvm::Value *num1 = m_utils.removeNaN(m_utils.castValue(arg1.second, arg1.first));
-                llvm::Value *num2 = m_utils.removeNaN(m_utils.castValue(arg2.second, arg2.first));
-                ins->functionReturnReg->value = m_builder.CreateFDiv(num1, num2);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::Random: {
-                assert(ins->args.size() == 2);
-                const auto &arg1 = ins->args[0];
-                const auto &arg2 = ins->args[1];
-                LLVMRegister *reg1 = arg1.second;
-                LLVMRegister *reg2 = arg2.second;
-
-                if (reg1->type() == Compiler::StaticType::Bool && reg2->type() == Compiler::StaticType::Bool) {
-                    llvm::Value *bool1 = m_utils.castValue(arg1.second, Compiler::StaticType::Bool);
-                    llvm::Value *bool2 = m_utils.castValue(arg2.second, Compiler::StaticType::Bool);
-                    ins->functionReturnReg->value = m_builder.CreateCall(m_utils.functions().resolve_llvm_random_bool(), { m_utils.executionContextPtr(), bool1, bool2 });
-                } else {
-                    llvm::Constant *inf = llvm::ConstantFP::getInfinity(m_builder.getDoubleTy(), false);
-                    llvm::Value *num1 = m_utils.removeNaN(m_utils.castValue(arg1.second, Compiler::StaticType::Number));
-                    llvm::Value *num2 = m_utils.removeNaN(m_utils.castValue(arg2.second, Compiler::StaticType::Number));
-                    llvm::Value *sum = m_builder.CreateFAdd(num1, num2);
-                    llvm::Value *sumDiv = m_builder.CreateFDiv(sum, inf);
-                    llvm::Value *isInfOrNaN = m_utils.isNaN(sumDiv);
-
-                    // NOTE: The random function will be called even in edge cases where it isn't needed, but they're rare, so it shouldn't be an issue
-                    if (reg1->type() == Compiler::StaticType::Number && reg2->type() == Compiler::StaticType::Number)
-                        ins->functionReturnReg->value =
-                            m_builder.CreateSelect(isInfOrNaN, sum, m_builder.CreateCall(m_utils.functions().resolve_llvm_random_double(), { m_utils.executionContextPtr(), num1, num2 }));
-                    else {
-                        llvm::Value *value1 = m_utils.createValue(reg1);
-                        llvm::Value *value2 = m_utils.createValue(reg2);
-                        ins->functionReturnReg->value =
-                            m_builder.CreateSelect(isInfOrNaN, sum, m_builder.CreateCall(m_utils.functions().resolve_llvm_random(), { m_utils.executionContextPtr(), value1, value2 }));
-                    }
-                }
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::RandomInt: {
-                assert(ins->args.size() == 2);
-                const auto &arg1 = ins->args[0];
-                const auto &arg2 = ins->args[1];
-                llvm::Value *from = m_builder.CreateFPToSI(m_utils.castValue(arg1.second, arg1.first), m_builder.getInt64Ty());
-                llvm::Value *to = m_builder.CreateFPToSI(m_utils.castValue(arg2.second, arg2.first), m_builder.getInt64Ty());
-                ins->functionReturnReg->value = m_builder.CreateCall(m_utils.functions().resolve_llvm_random_long(), { m_utils.executionContextPtr(), from, to });
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::CmpEQ: {
-                assert(ins->args.size() == 2);
-                const auto &arg1 = ins->args[0].second;
-                const auto &arg2 = ins->args[1].second;
-                ins->functionReturnReg->value = m_utils.createComparison(arg1, arg2, LLVMBuildUtils::Comparison::EQ);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::CmpGT: {
-                assert(ins->args.size() == 2);
-                const auto &arg1 = ins->args[0].second;
-                const auto &arg2 = ins->args[1].second;
-                ins->functionReturnReg->value = m_utils.createComparison(arg1, arg2, LLVMBuildUtils::Comparison::GT);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::CmpLT: {
-                assert(ins->args.size() == 2);
-                const auto &arg1 = ins->args[0].second;
-                const auto &arg2 = ins->args[1].second;
-                ins->functionReturnReg->value = m_utils.createComparison(arg1, arg2, LLVMBuildUtils::Comparison::LT);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::StrCmpEQCS: {
-                assert(ins->args.size() == 2);
-                const auto &arg1 = ins->args[0].second;
-                const auto &arg2 = ins->args[1].second;
-                ins->functionReturnReg->value = m_utils.createStringComparison(arg1, arg2, true);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::StrCmpEQCI: {
-                assert(ins->args.size() == 2);
-                const auto &arg1 = ins->args[0].second;
-                const auto &arg2 = ins->args[1].second;
-                ins->functionReturnReg->value = m_utils.createStringComparison(arg1, arg2, false);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::And: {
-                assert(ins->args.size() == 2);
-                const auto &arg1 = ins->args[0];
-                const auto &arg2 = ins->args[1];
-                llvm::Value *bool1 = m_utils.castValue(arg1.second, arg1.first);
-                llvm::Value *bool2 = m_utils.castValue(arg2.second, arg2.first);
-                ins->functionReturnReg->value = m_builder.CreateAnd(bool1, bool2);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::Or: {
-                assert(ins->args.size() == 2);
-                const auto &arg1 = ins->args[0];
-                const auto &arg2 = ins->args[1];
-                llvm::Value *bool1 = m_utils.castValue(arg1.second, arg1.first);
-                llvm::Value *bool2 = m_utils.castValue(arg2.second, arg2.first);
-                ins->functionReturnReg->value = m_builder.CreateOr(bool1, bool2);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::Not: {
-                assert(ins->args.size() == 1);
-                const auto &arg = ins->args[0];
-                llvm::Value *value = m_utils.castValue(arg.second, arg.first);
-                ins->functionReturnReg->value = m_builder.CreateNot(value);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::Mod: {
-                assert(ins->args.size() == 2);
-                const auto &arg1 = ins->args[0];
-                const auto &arg2 = ins->args[1];
-                // rem(a, b) / b < 0.0 ? rem(a, b) + b : rem(a, b)
-                llvm::Constant *zero = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0));
-                llvm::Value *num1 = m_utils.removeNaN(m_utils.castValue(arg1.second, arg1.first));
-                llvm::Value *num2 = m_utils.removeNaN(m_utils.castValue(arg2.second, arg2.first));
-                llvm::Value *value = m_builder.CreateFRem(num1, num2);                                // rem(a, b)
-                llvm::Value *cond = m_builder.CreateFCmpOLT(m_builder.CreateFDiv(value, num2), zero); // rem(a, b) / b < 0.0                                                            // rem(a, b)
-                ins->functionReturnReg->value = m_builder.CreateSelect(cond, m_builder.CreateFAdd(value, num2), value);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::Round: {
-                assert(ins->args.size() == 1);
-                const auto &arg = ins->args[0];
-                // x >= 0.0 ? round(x) : (x >= -0.5 ? -0.0 : floor(x + 0.5))
-                llvm::Constant *zero = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0));
-                llvm::Constant *negativeZero = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(-0.0));
-                llvm::Function *roundFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::round, m_builder.getDoubleTy());
-                llvm::Function *floorFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::floor, m_builder.getDoubleTy());
-                llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
-                llvm::Value *notNegative = m_builder.CreateFCmpOGE(num, zero);                                                                                 // num >= 0.0
-                llvm::Value *roundNum = m_builder.CreateCall(roundFunc, num);                                                                                  // round(num)
-                llvm::Value *negativeCond = m_builder.CreateFCmpOGE(num, llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(-0.5)));                               // num >= -0.5
-                llvm::Value *negativeRound = m_builder.CreateCall(floorFunc, m_builder.CreateFAdd(num, llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.5)))); // floor(x + 0.5)
-                ins->functionReturnReg->value = m_builder.CreateSelect(notNegative, roundNum, m_builder.CreateSelect(negativeCond, negativeZero, negativeRound));
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::Abs: {
-                assert(ins->args.size() == 1);
-                const auto &arg = ins->args[0];
-                llvm::Function *absFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::fabs, m_builder.getDoubleTy());
-                llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
-                ins->functionReturnReg->value = m_builder.CreateCall(absFunc, num);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::Floor: {
-                assert(ins->args.size() == 1);
-                const auto &arg = ins->args[0];
-                llvm::Function *floorFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::floor, m_builder.getDoubleTy());
-                llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
-                ins->functionReturnReg->value = m_builder.CreateCall(floorFunc, num);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::Ceil: {
-                assert(ins->args.size() == 1);
-                const auto &arg = ins->args[0];
-                llvm::Function *ceilFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::ceil, m_builder.getDoubleTy());
-                llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
-                ins->functionReturnReg->value = m_builder.CreateCall(ceilFunc, num);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::Sqrt: {
-                assert(ins->args.size() == 1);
-                const auto &arg = ins->args[0];
-                // sqrt(x) + 0.0
-                // This avoids negative zero
-                llvm::Constant *zero = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0));
-                llvm::Function *sqrtFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::sqrt, m_builder.getDoubleTy());
-                llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
-                ins->functionReturnReg->value = m_builder.CreateFAdd(m_builder.CreateCall(sqrtFunc, num), zero);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::Sin: {
-                assert(ins->args.size() == 1);
-                const auto &arg = ins->args[0];
-                // round(sin(x * pi / 180.0) * 1e10) / 1e10 + 0.0
-                // +0.0 to avoid -0.0
-                llvm::Constant *zero = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0));
-                llvm::Constant *pi = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(std::acos(-1.0)));
-                llvm::Constant *piDeg = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(180.0));
-                llvm::Constant *factor = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(1e10));
-                llvm::Function *sinFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::sin, m_builder.getDoubleTy());
-                llvm::Function *roundFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::round, m_builder.getDoubleTy());
-                llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
-                llvm::Value *sinResult = m_builder.CreateCall(sinFunc, m_builder.CreateFDiv(m_builder.CreateFMul(num, pi), piDeg)); // sin(x * pi / 180)
-                llvm::Value *rounded = m_builder.CreateCall(roundFunc, m_builder.CreateFMul(sinResult, factor));                    // round(sin(x * 180) * 1e10)
-                ins->functionReturnReg->value = m_builder.CreateFAdd(m_builder.CreateFDiv(rounded, factor), zero);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::Cos: {
-                assert(ins->args.size() == 1);
-                const auto &arg = ins->args[0];
-                // round(cos(x * pi / 180.0) * 1e10) / 1e10
-                llvm::Constant *pi = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(std::acos(-1.0)));
-                llvm::Constant *piDeg = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(180.0));
-                llvm::Constant *factor = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(1e10));
-                llvm::Function *cosFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::cos, m_builder.getDoubleTy());
-                llvm::Function *roundFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::round, m_builder.getDoubleTy());
-                llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
-                llvm::Value *cosResult = m_builder.CreateCall(cosFunc, m_builder.CreateFDiv(m_builder.CreateFMul(num, pi), piDeg)); // cos(x * pi / 180)
-                llvm::Value *rounded = m_builder.CreateCall(roundFunc, m_builder.CreateFMul(cosResult, factor));                    // round(cos(x * 180) * 1e10)
-                ins->functionReturnReg->value = m_builder.CreateFDiv(rounded, factor);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::Tan: {
-                assert(ins->args.size() == 1);
-                const auto &arg = ins->args[0];
-                // ((mod = rem(x, 360.0)) == -270.0 || mod == 90.0) ? inf : ((mod == -90.0 || mod == 270.0) ? -inf : round(tan(x * pi / 180.0) * 1e10) / 1e10 + 0.0)
-                // +0.0 to avoid -0.0
-                llvm::Constant *zero = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0));
-                llvm::Constant *full = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(360.0));
-                llvm::Constant *posInf = llvm::ConstantFP::getInfinity(m_builder.getDoubleTy(), false);
-                llvm::Constant *negInf = llvm::ConstantFP::getInfinity(m_builder.getDoubleTy(), true);
-                llvm::Constant *undefined1 = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(-270.0));
-                llvm::Constant *undefined2 = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(90.0));
-                llvm::Constant *undefined3 = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(-90.0));
-                llvm::Constant *undefined4 = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(270.0));
-                llvm::Constant *pi = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(std::acos(-1.0)));
-                llvm::Constant *piDeg = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(180.0));
-                llvm::Constant *factor = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(1e10));
-                llvm::Function *tanFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::tan, m_builder.getDoubleTy());
-                llvm::Function *roundFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::round, m_builder.getDoubleTy());
-                llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
-                llvm::Value *mod = m_builder.CreateFRem(num, full);
-                llvm::Value *isUndefined1 = m_builder.CreateFCmpOEQ(mod, undefined1);                                               // rem(x, 360.0) == -270.0
-                llvm::Value *isUndefined2 = m_builder.CreateFCmpOEQ(mod, undefined2);                                               // rem(x, 360.0) == 90.0
-                llvm::Value *isUndefined3 = m_builder.CreateFCmpOEQ(mod, undefined3);                                               // rem(x, 360.0) == -90.0
-                llvm::Value *isUndefined4 = m_builder.CreateFCmpOEQ(mod, undefined4);                                               // rem(x, 360.0) == 270.0
-                llvm::Value *tanResult = m_builder.CreateCall(tanFunc, m_builder.CreateFDiv(m_builder.CreateFMul(num, pi), piDeg)); // tan(x * pi / 180)
-                llvm::Value *rounded = m_builder.CreateCall(roundFunc, m_builder.CreateFMul(tanResult, factor));                    // round(tan(x * 180) * 1e10)
-                llvm::Value *result = m_builder.CreateFAdd(m_builder.CreateFDiv(rounded, factor), zero);                            // round(tan(x * pi / 180.0) * 1e10) / 1e10 + 0.0
-                llvm::Value *inner = m_builder.CreateSelect(m_builder.CreateOr(isUndefined3, isUndefined4), negInf, result);
-                ins->functionReturnReg->value = m_builder.CreateSelect(m_builder.CreateOr(isUndefined1, isUndefined2), posInf, inner);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::Asin: {
-                assert(ins->args.size() == 1);
-                const auto &arg = ins->args[0];
-                // asin(x) * 180.0 / pi + 0.0
-                // +0.0 to avoid -0.0
-                llvm::Constant *zero = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0));
-                llvm::Constant *pi = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(std::acos(-1.0)));
-                llvm::Constant *piDeg = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(180.0));
-                llvm::Function *asinFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::asin, m_builder.getDoubleTy());
-                llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
-                ins->functionReturnReg->value = m_builder.CreateFAdd(m_builder.CreateFDiv(m_builder.CreateFMul(m_builder.CreateCall(asinFunc, num), piDeg), pi), zero);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::Acos: {
-                assert(ins->args.size() == 1);
-                const auto &arg = ins->args[0];
-                // acos(x) * 180.0 / pi
-                llvm::Constant *pi = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(std::acos(-1.0)));
-                llvm::Constant *piDeg = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(180.0));
-                llvm::Function *acosFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::acos, m_builder.getDoubleTy());
-                llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
-                ins->functionReturnReg->value = m_builder.CreateFDiv(m_builder.CreateFMul(m_builder.CreateCall(acosFunc, num), piDeg), pi);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::Atan: {
-                assert(ins->args.size() == 1);
-                const auto &arg = ins->args[0];
-                // atan(x) * 180.0 / pi
-                llvm::Constant *pi = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(std::acos(-1.0)));
-                llvm::Constant *piDeg = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(180.0));
-                llvm::Function *atanFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::atan, m_builder.getDoubleTy());
-                llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
-                ins->functionReturnReg->value = m_builder.CreateFDiv(m_builder.CreateFMul(m_builder.CreateCall(atanFunc, num), piDeg), pi);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::Ln: {
-                assert(ins->args.size() == 1);
-                const auto &arg = ins->args[0];
-                // log(x)
-                llvm::Function *logFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::log, m_builder.getDoubleTy());
-                llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
-                ins->functionReturnReg->value = m_builder.CreateCall(logFunc, num);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::Log10: {
-                assert(ins->args.size() == 1);
-                const auto &arg = ins->args[0];
-                // log10(x)
-                llvm::Function *log10Func = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::log10, m_builder.getDoubleTy());
-                llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
-                ins->functionReturnReg->value = m_builder.CreateCall(log10Func, num);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::Exp: {
-                assert(ins->args.size() == 1);
-                const auto &arg = ins->args[0];
-                // exp(x)
-                llvm::Function *expFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::exp, m_builder.getDoubleTy());
-                llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
-                ins->functionReturnReg->value = m_builder.CreateCall(expFunc, num);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::Exp10: {
-                assert(ins->args.size() == 1);
-                const auto &arg = ins->args[0];
-                // exp10(x)
-                llvm::Function *expFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::exp10, m_builder.getDoubleTy());
-                llvm::Value *num = m_utils.removeNaN(m_utils.castValue(arg.second, arg.first));
-                ins->functionReturnReg->value = m_builder.CreateCall(expFunc, num);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::StringConcat: {
-                assert(ins->args.size() == 2);
-                const auto &arg1 = ins->args[0];
-                const auto &arg2 = ins->args[1];
-                llvm::Value *str1 = m_utils.castValue(arg1.second, arg1.first);
-                llvm::Value *str2 = m_utils.castValue(arg2.second, arg2.first);
-                llvm::PointerType *charPointerType = m_builder.getInt16Ty()->getPointerTo();
-                llvm::Function *memcpyFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::memcpy_inline, { charPointerType, charPointerType, m_builder.getInt64Ty() });
-
-                // StringPtr *result = string_pool_new(true)
-                llvm::Value *result = m_builder.CreateCall(m_utils.functions().resolve_string_pool_new(), m_builder.getInt1(true));
-                m_utils.freeStringLater(result);
-
-                // result->size = string1->size + string2->size
-                llvm::Value *sizeField1 = m_builder.CreateStructGEP(m_stringPtrType, str1, 1);
-                llvm::Value *sizeField2 = m_builder.CreateStructGEP(m_stringPtrType, str2, 1);
-                llvm::Value *size1 = m_builder.CreateLoad(m_builder.getInt64Ty(), sizeField1);
-                llvm::Value *size2 = m_builder.CreateLoad(m_builder.getInt64Ty(), sizeField2);
-                llvm::Value *resultSize = m_builder.CreateAdd(size1, size2);
-                llvm::Value *resultSizeField = m_builder.CreateStructGEP(m_stringPtrType, result, 1);
-                m_builder.CreateStore(resultSize, resultSizeField);
-
-                // string_alloc(result, result->size)
-                m_builder.CreateCall(m_utils.functions().resolve_string_alloc(), { result, resultSize });
-
-                // memcpy(result->data, string1->data, string1->size * sizeof(char16_t))
-                llvm::Value *dataField1 = m_builder.CreateStructGEP(m_stringPtrType, str1, 0);
-                llvm::Value *data1 = m_builder.CreateLoad(charPointerType, dataField1);
-                llvm::Value *resultDataField = m_builder.CreateStructGEP(m_stringPtrType, result, 0);
-                llvm::Value *writePtr = m_builder.CreateLoad(charPointerType, resultDataField);
-                m_builder.CreateCall(memcpyFunc, { writePtr, data1, m_builder.CreateMul(size1, m_builder.getInt64(2)), m_builder.getInt1(false) });
-
-                // memcpy(result->data + string1->size, string2->data, (string2->size + 1) * sizeof(char16_t))
-                // +1: null-terminate
-                llvm::Value *dataField2 = m_builder.CreateStructGEP(m_stringPtrType, str2, 0);
-                llvm::Value *data2 = m_builder.CreateLoad(charPointerType, dataField2);
-                writePtr = m_builder.CreateGEP(m_builder.getInt16Ty(), writePtr, size1);
-                m_builder.CreateCall(memcpyFunc, { writePtr, data2, m_builder.CreateMul(m_builder.CreateAdd(size2, m_builder.getInt64(1)), m_builder.getInt64(2)), m_builder.getInt1(false) });
-
-                ins->functionReturnReg->value = result;
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::StringChar: {
-                assert(ins->args.size() == 2);
-                const auto &arg1 = ins->args[0];
-                const auto &arg2 = ins->args[1];
-                llvm::Value *str = m_utils.castValue(arg1.second, arg1.first);
-                llvm::Value *index = m_builder.CreateFPToSI(m_utils.castValue(arg2.second, arg2.first), m_builder.getInt64Ty());
-                llvm::PointerType *charPointerType = m_builder.getInt16Ty()->getPointerTo();
-
-                // Get data ptr and size
-                llvm::Value *dataField = m_builder.CreateStructGEP(m_stringPtrType, str, 0);
-                llvm::Value *data = m_builder.CreateLoad(charPointerType, dataField);
-                llvm::Value *sizeField = m_builder.CreateStructGEP(m_stringPtrType, str, 1);
-                llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), sizeField);
-
-                // Check range, get character ptr
-                llvm::Value *inRange = m_builder.CreateAnd(m_builder.CreateICmpSGE(index, m_builder.getInt64(0)), m_builder.CreateICmpSLT(index, size));
-                llvm::Value *charPtr = m_builder.CreateGEP(m_builder.getInt16Ty(), data, index);
-
-                // Allocate string
-                llvm::Value *result = m_builder.CreateCall(m_utils.functions().resolve_string_pool_new(), m_builder.getInt1(true));
-                m_utils.freeStringLater(result);
-                m_builder.CreateCall(m_utils.functions().resolve_string_alloc(), { result, m_builder.getInt64(1) }); // size 1 to avoid branching
-
-                // Get result data ptr
-                dataField = m_builder.CreateStructGEP(m_stringPtrType, result, 0);
-                data = m_builder.CreateLoad(charPointerType, dataField);
-
-                // Write result
-                llvm::Value *char1 = m_builder.CreateGEP(m_builder.getInt16Ty(), data, m_builder.getInt64(0));
-                llvm::Value *char2 = m_builder.CreateGEP(m_builder.getInt16Ty(), data, m_builder.getInt64(1));
-                sizeField = m_builder.CreateStructGEP(m_stringPtrType, result, 1);
-                m_builder.CreateStore(m_builder.CreateSelect(inRange, m_builder.CreateLoad(m_builder.getInt16Ty(), charPtr), m_builder.getInt16(0)), char1);
-                m_builder.CreateStore(m_builder.getInt16(0), char2);
-                m_builder.CreateStore(m_builder.CreateSelect(inRange, m_builder.getInt64(1), m_builder.getInt64(0)), sizeField);
-
-                ins->functionReturnReg->value = result;
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::StringLength: {
-                assert(ins->args.size() == 1);
-                const auto &arg = ins->args[0];
-                llvm::Value *str = m_utils.castValue(arg.second, arg.first);
-                llvm::Value *sizeField = m_builder.CreateStructGEP(m_stringPtrType, str, 1);
-                llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), sizeField);
-                ins->functionReturnReg->value = m_builder.CreateSIToFP(size, m_builder.getDoubleTy());
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::Select: {
-                assert(ins->args.size() == 3);
-                const auto &arg1 = ins->args[0];
-                const auto &arg2 = ins->args[1];
-                const auto &arg3 = ins->args[2];
-                auto type = arg2.first;
-                llvm::Value *cond = m_utils.castValue(arg1.second, arg1.first);
-                llvm::Value *trueValue;
-                llvm::Value *falseValue;
-
-                if (type == Compiler::StaticType::Unknown) {
-                    trueValue = m_utils.createValue(arg2.second);
-                    falseValue = m_utils.createValue(arg3.second);
-                } else {
-                    trueValue = m_utils.castValue(arg2.second, type);
-                    falseValue = m_utils.castValue(arg3.second, type);
-                }
-
-                ins->functionReturnReg->value = m_builder.CreateSelect(cond, trueValue, falseValue);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::CreateLocalVariable: {
-                assert(ins->args.empty());
-                llvm::Type *type = nullptr;
-
-                switch (ins->functionReturnReg->type()) {
-                    case Compiler::StaticType::Number:
-                        type = m_builder.getDoubleTy();
-                        break;
-
-                    case Compiler::StaticType::Bool:
-                        type = m_builder.getInt1Ty();
-                        break;
-
-                    case Compiler::StaticType::String:
-                        std::cerr << "error: local variables do not support string type" << std::endl;
-                        break;
-
-                    case Compiler::StaticType::Pointer:
-                        std::cerr << "error: local variables do not support pointer type" << std::endl;
-                        break;
-
-                    default:
-                        assert(false);
-                        break;
-                }
-
-                ins->functionReturnReg->value = m_utils.addAlloca(type);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::WriteLocalVariable: {
-                assert(ins->args.size() == 2);
-                const auto &arg1 = ins->args[0];
-                const auto &arg2 = ins->args[1];
-                llvm::Value *converted = m_utils.castValue(arg2.second, arg2.first);
-                m_builder.CreateStore(converted, arg1.second->value);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::ReadLocalVariable: {
-                assert(ins->args.size() == 1);
-                const auto &arg = ins->args[0];
-                llvm::Type *type = nullptr;
-
-                switch (ins->functionReturnReg->type()) {
-                    case Compiler::StaticType::Number:
-                        type = m_builder.getDoubleTy();
-                        break;
-
-                    case Compiler::StaticType::Bool:
-                        type = m_builder.getInt1Ty();
-                        break;
-
-                    default:
-                        assert(false);
-                        break;
-                }
-
-                ins->functionReturnReg->value = m_builder.CreateLoad(type, arg.second->value);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::WriteVariable: {
-                assert(ins->args.size() == 1);
-                const auto &arg = ins->args[0];
-                Compiler::StaticType argType = m_utils.optimizeRegisterType(arg.second);
-                LLVMVariablePtr &varPtr = m_utils.variablePtr(ins->workVariable);
-                varPtr.changed = true; // TODO: Handle loops and if statements
-
-                Compiler::StaticType varType = Compiler::StaticType::Unknown;
-
-                if (m_warp)
-                    varType = m_typeAnalyzer.variableType(ins->workVariable, ins, Compiler::StaticType::Unknown);
-
-                // Initialize stack variable on first assignment
-                // TODO: Use stack in the top level (outside loops and if statements)
-                /*if (!varPtr.onStack) {
-                    varPtr.onStack = true;
-                    varPtr.type = type; // don't care about unknown type on first assignment
-
-                    ValueType mappedType;
-
-                    if (type == Compiler::StaticType::String || type == Compiler::StaticType::Unknown) {
-                        // Value functions are used for these types, so don't break them
-                        mappedType = ValueType::Number;
-                    } else {
-                        auto it = std::find_if(TYPE_MAP.begin(), TYPE_MAP.end(), [type](const std::pair<ValueType, Compiler::StaticType> &pair) { return pair.second == type; });
-                        assert(it != TYPE_MAP.cend());
-                        mappedType = it->first;
-                    }
-
-                    llvm::Value *typeField = m_builder.CreateStructGEP(m_valueDataType, varPtr.stackPtr, 1);
-                    m_builder.CreateStore(m_builder.getInt32(static_cast<uint32_t>(mappedType)), typeField);
-                }*/
-
-                m_utils.createValueStore(arg.second, varPtr.stackPtr, argType, varType);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::ReadVariable: {
-                assert(ins->args.size() == 0);
-                LLVMVariablePtr &varPtr = m_utils.variablePtr(ins->workVariable);
-                Compiler::StaticType type = Compiler::StaticType::Unknown;
-
-                if (m_warp)
-                    type = m_typeAnalyzer.variableType(ins->workVariable, ins, Compiler::StaticType::Unknown);
-
-                ins->functionReturnReg->value = varPtr.onStack && !(ins->loopCondition && !m_warp) ? varPtr.stackPtr : varPtr.heapPtr;
-                ins->functionReturnReg->setType(type);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::ClearList: {
-                assert(ins->args.size() == 0);
-                LLVMListPtr &listPtr = m_utils.listPtr(ins->workList);
-                m_builder.CreateCall(m_utils.functions().resolve_list_clear(), listPtr.ptr);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::RemoveListItem: {
-                assert(ins->args.size() == 1);
-                const auto &arg = ins->args[0];
-                LLVMListPtr &listPtr = m_utils.listPtr(ins->workList);
-
-                // Range check
-                llvm::Value *min = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0));
-                llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.sizePtr);
-                size = m_builder.CreateUIToFP(size, m_builder.getDoubleTy());
-                llvm::Value *index = m_utils.castValue(arg.second, arg.first);
-                llvm::Value *inRange = m_builder.CreateAnd(m_builder.CreateFCmpOGE(index, min), m_builder.CreateFCmpOLT(index, size));
-                llvm::BasicBlock *removeBlock = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-                llvm::BasicBlock *nextBlock = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-                m_builder.CreateCondBr(inRange, removeBlock, nextBlock);
-
-                // Remove
-                m_builder.SetInsertPoint(removeBlock);
-                index = m_builder.CreateFPToUI(m_utils.castValue(arg.second, arg.first), m_builder.getInt64Ty());
-                m_builder.CreateCall(m_utils.functions().resolve_list_remove(), { listPtr.ptr, index });
-                m_builder.CreateBr(nextBlock);
-
-                m_builder.SetInsertPoint(nextBlock);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::AppendToList: {
-                assert(ins->args.size() == 1);
-                const auto &arg = ins->args[0];
-                Compiler::StaticType type = m_utils.optimizeRegisterType(arg.second);
-                LLVMListPtr &listPtr = m_utils.listPtr(ins->workList);
-
-                Compiler::StaticType listType = Compiler::StaticType::Unknown;
-
-                if (m_warp)
-                    listType = m_typeAnalyzer.listType(ins->workList, ins, Compiler::StaticType::Unknown, false);
-
-                // Check if enough space is allocated
-                llvm::Value *allocatedSize = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.allocatedSizePtr);
-                llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.sizePtr);
-                llvm::Value *isAllocated = m_builder.CreateICmpUGT(allocatedSize, size);
-                llvm::BasicBlock *ifBlock = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-                llvm::BasicBlock *elseBlock = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-                llvm::BasicBlock *nextBlock = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-                m_builder.CreateCondBr(isAllocated, ifBlock, elseBlock);
-
-                // If there's enough space, use the allocated memory
-                m_builder.SetInsertPoint(ifBlock);
-                llvm::Value *itemPtr = m_utils.getListItem(listPtr, size);
-                m_utils.createReusedValueStore(arg.second, itemPtr, type, listType);
-                m_builder.CreateStore(m_builder.CreateAdd(size, m_builder.getInt64(1)), listPtr.sizePtr);
-                m_builder.CreateBr(nextBlock);
-
-                // Otherwise call appendEmpty()
-                m_builder.SetInsertPoint(elseBlock);
-                itemPtr = m_builder.CreateCall(m_utils.functions().resolve_list_append_empty(), listPtr.ptr);
-                m_utils.createReusedValueStore(arg.second, itemPtr, type, listType);
-                m_builder.CreateBr(nextBlock);
-
-                m_builder.SetInsertPoint(nextBlock);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::InsertToList: {
-                assert(ins->args.size() == 2);
-                const auto &indexArg = ins->args[0];
-                const auto &valueArg = ins->args[1];
-                Compiler::StaticType type = m_utils.optimizeRegisterType(valueArg.second);
-                LLVMListPtr &listPtr = m_utils.listPtr(ins->workList);
-
-                Compiler::StaticType listType = Compiler::StaticType::Unknown;
-
-                if (m_warp)
-                    listType = m_typeAnalyzer.listType(ins->workList, ins, Compiler::StaticType::Unknown, false);
-
-                // Range check
-                llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.sizePtr);
-                llvm::Value *min = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0));
-                size = m_builder.CreateUIToFP(size, m_builder.getDoubleTy());
-                llvm::Value *index = m_utils.castValue(indexArg.second, indexArg.first);
-                llvm::Value *inRange = m_builder.CreateAnd(m_builder.CreateFCmpOGE(index, min), m_builder.CreateFCmpOLE(index, size));
-                llvm::BasicBlock *insertBlock = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-                llvm::BasicBlock *nextBlock = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-                m_builder.CreateCondBr(inRange, insertBlock, nextBlock);
-
-                // Insert
-                m_builder.SetInsertPoint(insertBlock);
-                index = m_builder.CreateFPToUI(index, m_builder.getInt64Ty());
-                llvm::Value *itemPtr = m_builder.CreateCall(m_utils.functions().resolve_list_insert_empty(), { listPtr.ptr, index });
-                m_utils.createReusedValueStore(valueArg.second, itemPtr, type, listType);
-
-                m_builder.CreateBr(nextBlock);
-
-                m_builder.SetInsertPoint(nextBlock);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::ListReplace: {
-                assert(ins->args.size() == 2);
-                const auto &indexArg = ins->args[0];
-                const auto &valueArg = ins->args[1];
-                Compiler::StaticType type = m_utils.optimizeRegisterType(valueArg.second);
-                LLVMListPtr &listPtr = m_utils.listPtr(ins->workList);
-
-                Compiler::StaticType listType = Compiler::StaticType::Unknown;
-
-                if (m_warp)
-                    listType = m_typeAnalyzer.listType(ins->workList, ins, Compiler::StaticType::Unknown, false);
-
-                // Range check
-                llvm::Value *min = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0));
-                llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.sizePtr);
-                size = m_builder.CreateUIToFP(size, m_builder.getDoubleTy());
-                llvm::Value *index = m_utils.castValue(indexArg.second, indexArg.first);
-                llvm::Value *inRange = m_builder.CreateAnd(m_builder.CreateFCmpOGE(index, min), m_builder.CreateFCmpOLT(index, size));
-                llvm::BasicBlock *replaceBlock = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-                llvm::BasicBlock *nextBlock = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-                m_builder.CreateCondBr(inRange, replaceBlock, nextBlock);
-
-                // Replace
-                m_builder.SetInsertPoint(replaceBlock);
-                index = m_builder.CreateFPToUI(index, m_builder.getInt64Ty());
-                llvm::Value *itemPtr = m_utils.getListItem(listPtr, index);
-                m_utils.createValueStore(valueArg.second, itemPtr, type, listType);
-                m_builder.CreateBr(nextBlock);
-
-                m_builder.SetInsertPoint(nextBlock);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::GetListContents: {
-                assert(ins->args.size() == 0);
-                const LLVMListPtr &listPtr = m_utils.listPtr(ins->workList);
-                llvm::Value *ptr = m_builder.CreateCall(m_utils.functions().resolve_list_to_string(), listPtr.ptr);
-                m_utils.freeStringLater(ptr);
-                ins->functionReturnReg->value = ptr;
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::GetListItem: {
-                assert(ins->args.size() == 1);
-                const auto &arg = ins->args[0];
-                LLVMListPtr &listPtr = m_utils.listPtr(ins->workList);
-
-                Compiler::StaticType listType = Compiler::StaticType::Unknown;
-
-                if (m_warp)
-                    listType = m_typeAnalyzer.listType(ins->workList, ins, Compiler::StaticType::Unknown, false);
-
-                llvm::Value *min = llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0));
-                llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.sizePtr);
-                size = m_builder.CreateUIToFP(size, m_builder.getDoubleTy());
-                llvm::Value *index = m_utils.castValue(arg.second, arg.first);
-                llvm::Value *inRange = m_builder.CreateAnd(m_builder.CreateFCmpOGE(index, min), m_builder.CreateFCmpOLT(index, size));
-
-                LLVMConstantRegister nullReg(listType == Compiler::StaticType::Unknown ? Compiler::StaticType::Number : listType, Value());
-                llvm::Value *null = m_utils.createValue(static_cast<LLVMRegister *>(&nullReg));
-
-                index = m_builder.CreateFPToUI(index, m_builder.getInt64Ty());
-                ins->functionReturnReg->value = m_builder.CreateSelect(inRange, m_utils.getListItem(listPtr, index), null);
-                ins->functionReturnReg->setType(listType);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::GetListSize: {
-                assert(ins->args.size() == 0);
-                const LLVMListPtr &listPtr = m_utils.listPtr(ins->workList);
-                llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.sizePtr);
-                ins->functionReturnReg->value = m_builder.CreateUIToFP(size, m_builder.getDoubleTy());
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::GetListItemIndex: {
-                assert(ins->args.size() == 1);
-                const auto &arg = ins->args[0];
-                LLVMListPtr &listPtr = m_utils.listPtr(ins->workList);
-
-                Compiler::StaticType listType = Compiler::StaticType::Unknown;
-
-                if (m_warp)
-                    listType = m_typeAnalyzer.listType(ins->workList, ins, Compiler::StaticType::Unknown, false);
-
-                ins->functionReturnReg->value = m_builder.CreateSIToFP(m_utils.getListItemIndex(listPtr, listType, arg.second), m_builder.getDoubleTy());
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::ListContainsItem: {
-                assert(ins->args.size() == 1);
-                const auto &arg = ins->args[0];
-                LLVMListPtr &listPtr = m_utils.listPtr(ins->workList);
-
-                Compiler::StaticType listType = Compiler::StaticType::Unknown;
-
-                if (m_warp)
-                    listType = m_typeAnalyzer.listType(ins->workList, ins, Compiler::StaticType::Unknown, false);
-
-                llvm::Value *index = m_utils.getListItemIndex(listPtr, listType, arg.second);
-                ins->functionReturnReg->value = m_builder.CreateICmpSGT(index, llvm::ConstantInt::get(m_builder.getInt64Ty(), -1, true));
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::Yield:
-                createSuspend(coro.get(), m_utils.warpArg(), m_utils.targetVariables());
-
-                ins = ins->next;
-                break;
-
-            case LLVMInstruction::Type::BeginIf: {
-                LLVMIfStatement statement;
-                statement.beforeIf = m_builder.GetInsertBlock();
-                statement.body = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-
-                // Use last reg
-                assert(ins->args.size() == 1);
-                const auto &reg = ins->args[0];
-                assert(reg.first == Compiler::StaticType::Bool);
-                statement.condition = m_utils.castValue(reg.second, reg.first);
-
-                // Switch to body branch
-                m_builder.SetInsertPoint(statement.body);
-
-                ifStatements.push_back(statement);
-                m_utils.pushScopeLevel();
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::BeginElse: {
-                assert(!ifStatements.empty());
-                LLVMIfStatement &statement = ifStatements.back();
-
-                // Jump to the branch after the if statement
-                assert(!statement.afterIf);
-                statement.afterIf = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-                m_utils.freeScopeHeap();
-                m_builder.CreateBr(statement.afterIf);
-
-                // Create else branch
-                assert(!statement.elseBranch);
-                statement.elseBranch = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-
-                // Since there's an else branch, the conditional instruction should jump to it
-                m_builder.SetInsertPoint(statement.beforeIf);
-                m_builder.CreateCondBr(statement.condition, statement.body, statement.elseBranch);
-
-                // Switch to the else branch
-                m_builder.SetInsertPoint(statement.elseBranch);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::EndIf: {
-                assert(!ifStatements.empty());
-                LLVMIfStatement &statement = ifStatements.back();
-                m_utils.freeScopeHeap();
-
-                // Jump to the branch after the if statement
-                if (!statement.afterIf)
-                    statement.afterIf = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-
-                m_builder.CreateBr(statement.afterIf);
-
-                if (statement.elseBranch) {
-                } else {
-                    // If there wasn't an 'else' branch, create a conditional instruction which skips the if statement if false
-                    m_builder.SetInsertPoint(statement.beforeIf);
-                    m_builder.CreateCondBr(statement.condition, statement.body, statement.afterIf);
-                }
-
-                // Switch to the branch after the if statement
-                m_builder.SetInsertPoint(statement.afterIf);
-
-                ifStatements.pop_back();
-                m_utils.popScopeLevel();
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::BeginRepeatLoop: {
-                LLVMLoop loop;
-                loop.isRepeatLoop = true;
-
-                // index = 0
-                llvm::Constant *zero = llvm::ConstantInt::get(m_builder.getInt64Ty(), 0, true);
-                loop.index = m_utils.addAlloca(m_builder.getInt64Ty());
-                m_builder.CreateStore(zero, loop.index);
-
-                // Create branches
-                llvm::BasicBlock *roundBranch = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-                loop.conditionBranch = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-                loop.afterLoop = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-
-                // Use last reg for count
-                assert(ins->args.size() == 1);
-                const auto &reg = ins->args[0];
-                assert(reg.first == Compiler::StaticType::Number);
-                llvm::Value *count = m_utils.castValue(reg.second, reg.first);
-                llvm::Value *isInf = m_builder.CreateFCmpOEQ(count, llvm::ConstantFP::getInfinity(m_builder.getDoubleTy(), false));
-
-                // Clamp count if <= 0 (we can skip the loop if count is not positive)
-                llvm::Value *comparison = m_builder.CreateFCmpULE(count, llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0)));
-                m_builder.CreateCondBr(comparison, loop.afterLoop, roundBranch);
-
-                // Round (Scratch-specific behavior)
-                m_builder.SetInsertPoint(roundBranch);
-                llvm::Function *roundFunc = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::round, { count->getType() });
-                count = m_builder.CreateCall(roundFunc, { count });
-                count = m_builder.CreateFPToUI(count, m_builder.getInt64Ty()); // cast to unsigned integer
-                count = m_builder.CreateSelect(isInf, zero, count);
-
-                // Jump to condition branch
-                m_builder.CreateBr(loop.conditionBranch);
-
-                // Check index
-                m_builder.SetInsertPoint(loop.conditionBranch);
-
-                llvm::BasicBlock *body = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-
-                if (!loop.afterLoop)
-                    loop.afterLoop = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-
-                llvm::Value *currentIndex = m_builder.CreateLoad(m_builder.getInt64Ty(), loop.index);
-                comparison = m_builder.CreateOr(isInf, m_builder.CreateICmpULT(currentIndex, count));
-                m_builder.CreateCondBr(comparison, body, loop.afterLoop);
-
-                // Switch to body branch
-                m_builder.SetInsertPoint(body);
-
-                loops.push_back(loop);
-                m_utils.pushScopeLevel();
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::LoopIndex: {
-                assert(!loops.empty());
-                LLVMLoop &loop = loops.back();
-                llvm::Value *index = m_builder.CreateLoad(m_builder.getInt64Ty(), loop.index);
-                ins->functionReturnReg->value = m_builder.CreateUIToFP(index, m_builder.getDoubleTy());
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::BeginWhileLoop: {
-                assert(!loops.empty());
-                LLVMLoop &loop = loops.back();
-
-                // Create branches
-                llvm::BasicBlock *body = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-                loop.afterLoop = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-
-                // Use last reg
-                assert(ins->args.size() == 1);
-                const auto &reg = ins->args[0];
-                assert(reg.first == Compiler::StaticType::Bool);
-                llvm::Value *condition = m_utils.castValue(reg.second, reg.first);
-                m_builder.CreateCondBr(condition, body, loop.afterLoop);
-
-                // Switch to body branch
-                m_builder.SetInsertPoint(body);
-                m_utils.pushScopeLevel();
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::BeginRepeatUntilLoop: {
-                assert(!loops.empty());
-                LLVMLoop &loop = loops.back();
-
-                // Create branches
-                llvm::BasicBlock *body = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-                loop.afterLoop = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-
-                // Use last reg
-                assert(ins->args.size() == 1);
-                const auto &reg = ins->args[0];
-                assert(reg.first == Compiler::StaticType::Bool);
-                llvm::Value *condition = m_utils.castValue(reg.second, reg.first);
-                m_builder.CreateCondBr(condition, loop.afterLoop, body);
-
-                // Switch to body branch
-                m_builder.SetInsertPoint(body);
-                m_utils.pushScopeLevel();
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::BeginLoopCondition: {
-                LLVMLoop loop;
-                loop.isRepeatLoop = false;
-                loop.conditionBranch = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-                m_builder.CreateBr(loop.conditionBranch);
-                m_builder.SetInsertPoint(loop.conditionBranch);
-                loops.push_back(loop);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::EndLoop: {
-                assert(!loops.empty());
-                LLVMLoop &loop = loops.back();
-
-                if (loop.isRepeatLoop) {
-                    // Increment index
-                    llvm::Value *currentIndex = m_builder.CreateLoad(m_builder.getInt64Ty(), loop.index);
-                    llvm::Value *incremented = m_builder.CreateAdd(currentIndex, llvm::ConstantInt::get(m_builder.getInt64Ty(), 1, false));
-                    m_builder.CreateStore(incremented, loop.index);
-                }
-
-                // Jump to the condition branch
-                m_utils.freeScopeHeap();
-                m_builder.CreateBr(loop.conditionBranch);
-
-                // Switch to the branch after the loop
-                m_builder.SetInsertPoint(loop.afterLoop);
-
-                loops.pop_back();
-                m_utils.popScopeLevel();
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::Stop: {
-                m_utils.freeScopeHeap();
-                m_builder.CreateBr(endBranch);
-                llvm::BasicBlock *nextBranch = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-                m_builder.SetInsertPoint(nextBranch);
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::CallProcedure: {
-                assert(ins->procedurePrototype);
-                assert(ins->args.size() == ins->procedurePrototype->argumentTypes().size());
-                m_utils.freeScopeHeap();
-                m_utils.syncVariables(m_utils.targetVariables());
-
-                std::string name = getMainFunctionName(ins->procedurePrototype);
-                llvm::FunctionType *type = getMainFunctionType(ins->procedurePrototype);
-                std::vector<llvm::Value *> args;
-
-                for (size_t i = 0; i < m_defaultArgCount; i++)
-                    args.push_back(m_function->getArg(i));
-
-                // Add warp arg
-                if (m_warp)
-                    args.push_back(m_builder.getInt1(true));
-                else
-                    args.push_back(m_utils.procedurePrototype() ? m_utils.warpArg() : m_builder.getInt1(false));
-
-                // Add procedure args
-                for (const auto &arg : ins->args) {
-                    if (arg.first == Compiler::StaticType::Unknown)
-                        args.push_back(m_utils.createValue(arg.second));
-                    else
-                        args.push_back(m_utils.castValue(arg.second, arg.first));
-                }
-
-                llvm::Value *handle = m_builder.CreateCall(m_utils.functions().resolveFunction(name, type), args);
-
-                if (!m_warp && !ins->procedurePrototype->warp()) {
-                    llvm::BasicBlock *suspendBranch = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-                    llvm::BasicBlock *nextBranch = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-                    m_builder.CreateCondBr(m_builder.CreateIsNull(handle), nextBranch, suspendBranch);
-
-                    m_builder.SetInsertPoint(suspendBranch);
-                    createSuspend(coro.get(), m_utils.warpArg(), m_utils.targetVariables());
-                    llvm::Value *done = m_builder.CreateCall(m_ctx->coroutineResumeFunction(), { handle });
-                    m_builder.CreateCondBr(done, nextBranch, suspendBranch);
-
-                    m_builder.SetInsertPoint(nextBranch);
-                }
-
-                m_utils.reloadVariables(m_utils.targetVariables());
-
-                ins = ins->next;
-                break;
-            }
-
-            case LLVMInstruction::Type::ProcedureArg: {
-                assert(m_procedurePrototype);
-                llvm::Value *arg = m_function->getArg(m_defaultArgCount + 1 + ins->procedureArgIndex); // omit warp arg
-                ins->functionReturnReg->value = arg;
-
-                ins = ins->next;
-                break;
-            }
-        }
-    }
-
-    m_utils.end();
-    m_builder.CreateBr(endBranch);
-
-    m_builder.SetInsertPoint(endBranch);
-    m_utils.syncVariables(m_utils.targetVariables());
-
-    // End and verify the function
-    llvm::PointerType *pointerType = llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0);
-
-    switch (m_codeType) {
-        case Compiler::CodeType::Script:
-            if (m_warp)
-                m_builder.CreateRet(llvm::ConstantPointerNull::get(pointerType));
-            else
-                coro->end();
-            break;
-
-        case Compiler::CodeType::Reporter: {
-            // Use last instruction return value (or last constant) and create a ValueData instance
-            assert(!m_instructions.empty() || m_lastConstValue);
-            LLVMRegister *ret = m_instructions.empty() ? m_lastConstValue : m_instructions.last()->functionReturnReg;
-            llvm::Value *copy = m_utils.createNewValue(ret);
-            m_builder.CreateRet(m_builder.CreateLoad(m_valueDataType, copy));
-            break;
-        }
-
-        case Compiler::CodeType::HatPredicate:
-            // Use last instruction return value (or last constant)
-            assert(!m_instructions.empty() || m_lastConstValue);
-
-            if (m_instructions.empty())
-                m_builder.CreateRet(m_utils.castValue(m_lastConstValue, Compiler::StaticType::Bool));
-            else
-                m_builder.CreateRet(m_utils.castValue(m_instructions.last()->functionReturnReg, Compiler::StaticType::Bool));
-            break;
-    }
+    while (ins)
+        ins = m_instructionBuilder.process(ins);
 
+    m_utils.end(m_instructions.empty() ? nullptr : m_instructions.last(), m_lastConstValue);
     verifyFunction(m_function);
 
     return std::make_shared<LLVMExecutableCode>(m_ctx, m_function->getName().str(), m_ctx->coroutineResumeFunction()->getName().str(), m_codeType);
@@ -1846,66 +565,6 @@ void LLVMCodeBuilder::initTypes()
     m_stringPtrType = m_ctx->stringPtrType();
 }
 
-std::string LLVMCodeBuilder::getMainFunctionName(BlockPrototype *procedurePrototype)
-{
-    std::string name;
-
-    switch (m_codeType) {
-        case Compiler::CodeType::Script:
-            name = "script";
-            break;
-
-        case Compiler::CodeType::Reporter:
-            name = "reporter";
-            break;
-
-        case Compiler::CodeType::HatPredicate:
-            name = "predicate";
-            break;
-    }
-
-    return procedurePrototype ? "proc." + procedurePrototype->procCode() : name;
-}
-
-llvm::FunctionType *LLVMCodeBuilder::getMainFunctionType(BlockPrototype *procedurePrototype)
-{
-    // void *f(ExecutionContext *, Target *, ValueData **, List **, (warp arg), (procedure args...))
-    // ValueData f(...) (reporters)
-    // bool f(...) (hat predicates)
-    llvm::Type *pointerType = llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0);
-    std::vector<llvm::Type *> argTypes = { pointerType, pointerType, pointerType, pointerType };
-
-    if (procedurePrototype) {
-        argTypes.push_back(m_builder.getInt1Ty()); // warp arg (only in procedures)
-        const auto &types = procedurePrototype->argumentTypes();
-
-        for (BlockPrototype::ArgType type : types) {
-            if (type == BlockPrototype::ArgType::Bool)
-                argTypes.push_back(m_builder.getInt1Ty());
-            else
-                argTypes.push_back(m_valueDataType->getPointerTo());
-        }
-    }
-
-    llvm::Type *retType = nullptr;
-
-    switch (m_codeType) {
-        case Compiler::CodeType::Script:
-            retType = pointerType;
-            break;
-
-        case Compiler::CodeType::Reporter:
-            retType = m_valueDataType;
-            break;
-
-        case Compiler::CodeType::HatPredicate:
-            retType = m_builder.getInt1Ty();
-            break;
-    }
-
-    return llvm::FunctionType::get(retType, argTypes, false);
-}
-
 llvm::Function *LLVMCodeBuilder::getOrCreateFunction(const std::string &name, llvm::FunctionType *type)
 {
     llvm::Function *func = m_module->getFunction(name);
@@ -1974,26 +633,3 @@ LLVMRegister *LLVMCodeBuilder::createOp(const LLVMInstruction &ins, Compiler::St
 
     return nullptr;
 }
-
-void LLVMCodeBuilder::createSuspend(LLVMCoroutine *coro, llvm::Value *warpArg, llvm::Value *targetVariables)
-{
-    if (!m_warp) {
-        llvm::BasicBlock *suspendBranch, *nextBranch;
-
-        if (warpArg) {
-            suspendBranch = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-            nextBranch = llvm::BasicBlock::Create(m_llvmCtx, "", m_function);
-            m_builder.CreateCondBr(warpArg, nextBranch, suspendBranch);
-            m_builder.SetInsertPoint(suspendBranch);
-        }
-
-        m_utils.syncVariables(targetVariables);
-        coro->createSuspend();
-        m_utils.reloadVariables(targetVariables);
-
-        if (warpArg) {
-            m_builder.CreateBr(nextBranch);
-            m_builder.SetInsertPoint(nextBranch);
-        }
-    }
-}
diff --git a/src/engine/internal/llvm/llvmcodebuilder.h b/src/engine/internal/llvm/llvmcodebuilder.h
index 4137107c..37b04c6a 100644
--- a/src/engine/internal/llvm/llvmcodebuilder.h
+++ b/src/engine/internal/llvm/llvmcodebuilder.h
@@ -16,8 +16,8 @@
 #include "llvmcoroutine.h"
 #include "llvmvariableptr.h"
 #include "llvmlistptr.h"
-#include "llvmtypeanalyzer.h"
 #include "llvmfunctions.h"
+#include "instructions/instructionbuilder.h"
 
 namespace libscratchcpp
 {
@@ -117,8 +117,6 @@ class LLVMCodeBuilder : public ICodeBuilder
     private:
         void initTypes();
 
-        std::string getMainFunctionName(BlockPrototype *procedurePrototype);
-        llvm::FunctionType *getMainFunctionType(BlockPrototype *procedurePrototype);
         llvm::Function *getOrCreateFunction(const std::string &name, llvm::FunctionType *type);
         void verifyFunction(llvm::Function *func);
 
@@ -131,8 +129,6 @@ class LLVMCodeBuilder : public ICodeBuilder
         LLVMRegister *createOp(const LLVMInstruction &ins, Compiler::StaticType retType, Compiler::StaticType argType, const Compiler::Args &args);
         LLVMRegister *createOp(const LLVMInstruction &ins, Compiler::StaticType retType, const Compiler::ArgTypes &argTypes = {}, const Compiler::Args &args = {});
 
-        void createSuspend(LLVMCoroutine *coro, llvm::Value *warpArg, llvm::Value *targetVariables);
-
         Target *m_target = nullptr;
 
         LLVMCompilerContext *m_ctx;
@@ -141,7 +137,6 @@ class LLVMCodeBuilder : public ICodeBuilder
         llvm::IRBuilder<> m_builder;
         llvm::Function *m_function = nullptr;
         LLVMBuildUtils m_utils;
-        LLVMTypeAnalyzer m_typeAnalyzer;
 
         llvm::StructType *m_valueDataType = nullptr;
         llvm::StructType *m_stringPtrType = nullptr;
@@ -153,10 +148,11 @@ class LLVMCodeBuilder : public ICodeBuilder
         BlockPrototype *m_procedurePrototype = nullptr;
         bool m_defaultWarp = false;
         bool m_warp = false;
-        int m_defaultArgCount = 0;
         Compiler::CodeType m_codeType = Compiler::CodeType::Script;
 
         bool m_loopCondition = false; // whether we're currently compiling a loop condition
+
+        llvmins::InstructionBuilder m_instructionBuilder;
 };
 
 } // namespace libscratchcpp

From c28d358269b372b859857ce5ade469759fdb7827 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Tue, 5 Aug 2025 13:01:20 +0200
Subject: [PATCH 78/79] Rename code builder finalize method to build

---
 src/engine/compiler.cpp                      |   4 +-
 src/engine/internal/icodebuilder.h           |   2 +-
 src/engine/internal/llvm/llvmcodebuilder.cpp |   2 +-
 src/engine/internal/llvm/llvmcodebuilder.h   |   2 +-
 test/compiler/compiler_test.cpp              |   2 +-
 test/llvm/llvmcodebuilder_test.cpp           | 108 +++++++++----------
 test/llvm/llvmtestutils.cpp                  |   4 +-
 test/mocks/codebuildermock.h                 |   2 +-
 test/scratch_classes/inputvalue_test.cpp     |   2 +-
 9 files changed, 64 insertions(+), 64 deletions(-)

diff --git a/src/engine/compiler.cpp b/src/engine/compiler.cpp
index a7b40c25..90f95afe 100644
--- a/src/engine/compiler.cpp
+++ b/src/engine/compiler.cpp
@@ -83,7 +83,7 @@ std::shared_ptr<ExecutableCode> Compiler::compile(Block *startBlock, CodeType co
         }
 
         impl->block = nullptr;
-        return impl->builder->finalize();
+        return impl->builder->build();
     }
 
     while (impl->block) {
@@ -122,7 +122,7 @@ std::shared_ptr<ExecutableCode> Compiler::compile(Block *startBlock, CodeType co
             impl->substackEnd();
     }
 
-    return impl->builder->finalize();
+    return impl->builder->build();
 }
 
 /*!
diff --git a/src/engine/internal/icodebuilder.h b/src/engine/internal/icodebuilder.h
index 0170aa8b..d175c850 100644
--- a/src/engine/internal/icodebuilder.h
+++ b/src/engine/internal/icodebuilder.h
@@ -18,7 +18,7 @@ class ICodeBuilder
     public:
         virtual ~ICodeBuilder() { }
 
-        virtual std::shared_ptr<ExecutableCode> finalize() = 0;
+        virtual std::shared_ptr<ExecutableCode> build() = 0;
 
         virtual CompilerValue *addFunctionCall(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) = 0;
         virtual CompilerValue *addTargetFunctionCall(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) = 0;
diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp
index d1481de8..e5cc10a1 100644
--- a/src/engine/internal/llvm/llvmcodebuilder.cpp
+++ b/src/engine/internal/llvm/llvmcodebuilder.cpp
@@ -37,7 +37,7 @@ LLVMCodeBuilder::LLVMCodeBuilder(LLVMCompilerContext *ctx, BlockPrototype *proce
     initTypes();
 }
 
-std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
+std::shared_ptr<ExecutableCode> LLVMCodeBuilder::build()
 {
     if (!m_warp) {
         // Do not create coroutine if there are no yield instructions nor non-warp procedure calls
diff --git a/src/engine/internal/llvm/llvmcodebuilder.h b/src/engine/internal/llvm/llvmcodebuilder.h
index 37b04c6a..ecb1f4bf 100644
--- a/src/engine/internal/llvm/llvmcodebuilder.h
+++ b/src/engine/internal/llvm/llvmcodebuilder.h
@@ -30,7 +30,7 @@ class LLVMCodeBuilder : public ICodeBuilder
     public:
         LLVMCodeBuilder(LLVMCompilerContext *ctx, BlockPrototype *procedurePrototype = nullptr, Compiler::CodeType codeType = Compiler::CodeType::Script);
 
-        std::shared_ptr<ExecutableCode> finalize() override;
+        std::shared_ptr<ExecutableCode> build() override;
 
         CompilerValue *addFunctionCall(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) override;
         CompilerValue *addTargetFunctionCall(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) override;
diff --git a/test/compiler/compiler_test.cpp b/test/compiler/compiler_test.cpp
index 87d40c60..55d8d161 100644
--- a/test/compiler/compiler_test.cpp
+++ b/test/compiler/compiler_test.cpp
@@ -50,7 +50,7 @@ class CompilerTest : public testing::Test
         {
             ASSERT_EQ(compiler->block(), nullptr);
             EXPECT_CALL(m_builderFactory, create(m_ctx.get(), procedurePrototype, codeType)).WillOnce(Return(m_builder));
-            EXPECT_CALL(*m_builder, finalize()).WillOnce(Return(m_code));
+            EXPECT_CALL(*m_builder, build()).WillOnce(Return(m_code));
             ASSERT_EQ(compiler->compile(block, codeType), m_code);
             ASSERT_EQ(compiler->block(), nullptr);
         }
diff --git a/test/llvm/llvmcodebuilder_test.cpp b/test/llvm/llvmcodebuilder_test.cpp
index 5d18511f..50163908 100644
--- a/test/llvm/llvmcodebuilder_test.cpp
+++ b/test/llvm/llvmcodebuilder_test.cpp
@@ -137,7 +137,7 @@ TEST_F(LLVMCodeBuilderTest, FunctionCalls)
         v = m_builder->addFunctionCall("test_const_bool", Compiler::StaticType::Bool, { Compiler::StaticType::Bool }, { v });
         m_builder->addFunctionCall("test_print_unknown", Compiler::StaticType::Void, { Compiler::StaticType::Unknown }, { v });
 
-        auto code = m_builder->finalize();
+        auto code = m_builder->build();
         Script script(&m_target, nullptr, nullptr);
         script.setCode(code);
         Thread thread(&m_target, nullptr, &script);
@@ -185,7 +185,7 @@ TEST_F(LLVMCodeBuilderTest, FunctionCallsWithPointers)
 
     m_builder->addFunctionCall("test_print_pointer", Compiler::StaticType::Void, { Compiler::StaticType::Pointer }, { v });
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&m_target, nullptr, nullptr);
     script.setCode(code);
     Thread thread(&m_target, nullptr, &script);
@@ -228,7 +228,7 @@ TEST_F(LLVMCodeBuilderTest, ConstCasting)
     v = m_builder->addConstValue("hello world");
     m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&m_target, nullptr, nullptr);
     script.setCode(code);
     Thread thread(&m_target, nullptr, &script);
@@ -317,7 +317,7 @@ TEST_F(LLVMCodeBuilderTest, RawValueCasting)
     v = callConstFuncForType(ValueType::String, v);
     m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&m_target, nullptr, nullptr);
     script.setCode(code);
     Thread thread(&m_target, nullptr, &script);
@@ -390,7 +390,7 @@ TEST_F(LLVMCodeBuilderTest, LocalVariables)
         "true\n"
         "false\n";
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     Thread thread(&sprite, nullptr, &script);
@@ -447,7 +447,7 @@ TEST_F(LLVMCodeBuilderTest, WriteVariable)
     v = callConstFuncForType(ValueType::Bool, v);
     m_builder->createVariableWrite(localVar3.get(), v);
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -539,7 +539,7 @@ TEST_F(LLVMCodeBuilderTest, Select)
         "test\n"
         "true\n";
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -599,7 +599,7 @@ TEST_F(LLVMCodeBuilderTest, ReadVariable)
     expected += localVar2->value().toString() + '\n';
     expected += localVar3->value().toString() + '\n';
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -631,7 +631,7 @@ TEST_F(LLVMCodeBuilderTest, SyncVariablesBeforeCallingFunction)
     v = m_builder->addConstValue(456);
     m_builder->createVariableWrite(var.get(), v);
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
 
@@ -683,7 +683,7 @@ TEST_F(LLVMCodeBuilderTest, CastNonRawValueToUnknownType)
     expected += "Hello world\n";
     expected += "true\n";
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     Thread thread(&sprite, nullptr, &script);
@@ -753,7 +753,7 @@ TEST_F(LLVMCodeBuilderTest, ClearList)
     m_builder->createListClear(localList1.get());
     m_builder->createListClear(localList2.get());
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -815,7 +815,7 @@ TEST_F(LLVMCodeBuilderTest, RemoveFromList)
     v = m_builder->addConstValue(4);
     m_builder->createListRemove(localList.get(), v);
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -874,7 +874,7 @@ TEST_F(LLVMCodeBuilderTest, AppendToList)
     v = m_builder->addConstValue("hello world");
     m_builder->createListAppend(localList.get(), v);
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -951,7 +951,7 @@ TEST_F(LLVMCodeBuilderTest, InsertToList)
     v2 = m_builder->addConstValue(123);
     m_builder->createListInsert(localList.get(), v1, v2);
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -1018,7 +1018,7 @@ TEST_F(LLVMCodeBuilderTest, ListReplace)
     v2 = m_builder->addConstValue(123);
     m_builder->createListReplace(localList.get(), v1, v2);
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -1067,7 +1067,7 @@ TEST_F(LLVMCodeBuilderTest, GetListContents)
         "123\n"
         "Lorem ipsum dolor sit\n";
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -1192,7 +1192,7 @@ TEST_F(LLVMCodeBuilderTest, GetListItem)
         "0\n"
         "0\n";
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -1242,7 +1242,7 @@ TEST_F(LLVMCodeBuilderTest, GetListSize)
         "3\n"
         "4\n";
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -1336,7 +1336,7 @@ TEST_F(LLVMCodeBuilderTest, GetListItemIndex)
         "-1\n"
         "-1\n";
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -1430,7 +1430,7 @@ TEST_F(LLVMCodeBuilderTest, ListContainsItem)
         "false\n"
         "false\n";
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -1476,7 +1476,7 @@ TEST_F(LLVMCodeBuilderTest, Yield)
     createBuilder(false);
     build();
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&m_target, nullptr, nullptr);
     script.setCode(code);
     Thread thread(&m_target, nullptr, &script);
@@ -1536,7 +1536,7 @@ TEST_F(LLVMCodeBuilderTest, Yield)
     // With warp
     createBuilder(true);
     build();
-    code = m_builder->finalize();
+    code = m_builder->build();
     ctx = code->createExecutionContext(&thread);
 
     static const std::string expected =
@@ -1620,7 +1620,7 @@ TEST_F(LLVMCodeBuilderTest, VariablesAfterSuspend)
         "hello world\n"
         "-4.8\n";
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -1761,7 +1761,7 @@ TEST_F(LLVMCodeBuilderTest, ListsAfterSuspend)
         "-5.48\n"
         "hello\n";
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -1942,7 +1942,7 @@ TEST_F(LLVMCodeBuilderTest, IfStatement)
     }
     m_builder->endIf();
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&m_target, nullptr, nullptr);
     script.setCode(code);
     Thread thread(&m_target, nullptr, &script);
@@ -2059,7 +2059,7 @@ TEST_F(LLVMCodeBuilderTest, IfStatementVariables)
         "true\n"
         "true\n";
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -2199,7 +2199,7 @@ TEST_F(LLVMCodeBuilderTest, IfStatementLists)
         "hello\n"
         "false\n";
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -2282,7 +2282,7 @@ TEST_F(LLVMCodeBuilderTest, RepeatLoop)
     // str should still be allocated
     m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { str });
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&m_target, nullptr, nullptr);
     script.setCode(code);
     Thread thread(&m_target, nullptr, &script);
@@ -2330,7 +2330,7 @@ TEST_F(LLVMCodeBuilderTest, RepeatLoop)
     m_builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
     m_builder->endLoop();
 
-    code = m_builder->finalize();
+    code = m_builder->build();
     ctx = code->createExecutionContext(&thread);
 
     static const std::string expected1 = "no_args\n";
@@ -2356,7 +2356,7 @@ TEST_F(LLVMCodeBuilderTest, RepeatLoop)
     m_builder->beginRepeatLoop(v);
     m_builder->endLoop();
 
-    code = m_builder->finalize();
+    code = m_builder->build();
     ctx = code->createExecutionContext(&thread);
     code->run(ctx.get());
     ASSERT_TRUE(code->isFinished(ctx.get()));
@@ -2369,7 +2369,7 @@ TEST_F(LLVMCodeBuilderTest, RepeatLoop)
     m_builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
     m_builder->endLoop();
 
-    code = m_builder->finalize();
+    code = m_builder->build();
     ctx = code->createExecutionContext(&thread);
 
     for (int i = 0; i < 10; i++) {
@@ -2442,7 +2442,7 @@ TEST_F(LLVMCodeBuilderTest, WhileLoop)
     }
     m_builder->endLoop();
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&m_target, nullptr, nullptr);
     script.setCode(code);
     Thread thread(&m_target, nullptr, &script);
@@ -2470,7 +2470,7 @@ TEST_F(LLVMCodeBuilderTest, WhileLoop)
     m_builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
     m_builder->endLoop();
 
-    code = m_builder->finalize();
+    code = m_builder->build();
     ctx = code->createExecutionContext(&thread);
 
     static const std::string expected1 = "no_args\n";
@@ -2550,7 +2550,7 @@ TEST_F(LLVMCodeBuilderTest, RepeatUntilLoop)
     }
     m_builder->endLoop();
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&m_target, nullptr, nullptr);
     script.setCode(code);
     Thread thread(&m_target, nullptr, &script);
@@ -2578,7 +2578,7 @@ TEST_F(LLVMCodeBuilderTest, RepeatUntilLoop)
     m_builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
     m_builder->endLoop();
 
-    code = m_builder->finalize();
+    code = m_builder->build();
     ctx = code->createExecutionContext(&thread);
 
     static const std::string expected1 = "no_args\n";
@@ -2715,7 +2715,7 @@ TEST_F(LLVMCodeBuilderTest, LoopVariables)
         "true\n"
         "true\n";
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -2761,7 +2761,7 @@ TEST_F(LLVMCodeBuilderTest, VariableLoopTypeAnalysis)
         "5.25\n"
         "0\n";
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     Thread thread(&sprite, nullptr, &script);
@@ -2953,7 +2953,7 @@ TEST_F(LLVMCodeBuilderTest, LoopLists)
         "world\n"
         "false\n";
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -3012,7 +3012,7 @@ TEST_F(LLVMCodeBuilderTest, ListLoopTypeAnalysis)
         "0\n"
         "1\n";
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     Thread thread(&sprite, nullptr, &script);
@@ -3037,7 +3037,7 @@ TEST_F(LLVMCodeBuilderTest, StopNoWarp)
 
     std::string expected = "";
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     Thread thread(&sprite, nullptr, &script);
@@ -3061,7 +3061,7 @@ TEST_F(LLVMCodeBuilderTest, StopWarp)
 
     std::string expected = "";
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     Thread thread(&sprite, nullptr, &script);
@@ -3081,7 +3081,7 @@ TEST_F(LLVMCodeBuilderTest, StopAndReturn)
 
     std::string expected = "no_args\n";
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     Thread thread(&sprite, nullptr, &script);
@@ -3101,7 +3101,7 @@ TEST_F(LLVMCodeBuilderTest, MultipleScripts)
     CompilerValue *v = m_builder->addConstValue("script1");
     m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    auto code1 = m_builder->finalize();
+    auto code1 = m_builder->build();
 
     // Script 2
     createBuilder(&sprite, nullptr);
@@ -3109,7 +3109,7 @@ TEST_F(LLVMCodeBuilderTest, MultipleScripts)
     v = m_builder->addConstValue("script2");
     m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    auto code2 = m_builder->finalize();
+    auto code2 = m_builder->build();
 
     Script script1(&sprite, nullptr, nullptr);
     script1.setCode(code1);
@@ -3168,7 +3168,7 @@ TEST_F(LLVMCodeBuilderTest, Procedures)
     v = m_builder->addProcedureArgument("invalid");
     m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    m_builder->finalize();
+    m_builder->build();
 
     // Procedure 2
     BlockPrototype prototype2;
@@ -3181,7 +3181,7 @@ TEST_F(LLVMCodeBuilderTest, Procedures)
     m_builder->createProcedureCall(&prototype1, { m_builder->addConstValue(-652.3), m_builder->addConstValue(false), m_builder->addConstValue(true) });
     m_builder->endLoop();
 
-    m_builder->finalize();
+    m_builder->build();
 
     // Script
     createBuilder(&sprite, false);
@@ -3217,7 +3217,7 @@ TEST_F(LLVMCodeBuilderTest, Procedures)
         "0\n"
         "0\n";
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     Thread thread(&sprite, nullptr, &script);
@@ -3248,7 +3248,7 @@ TEST_F(LLVMCodeBuilderTest, HatPredicates)
 
     m_builder->addConstValue(true);
 
-    auto code1 = m_builder->finalize();
+    auto code1 = m_builder->build();
 
     // Predicate 2
     createPredicateBuilder(&sprite);
@@ -3256,7 +3256,7 @@ TEST_F(LLVMCodeBuilderTest, HatPredicates)
     CompilerValue *v = m_builder->addConstValue(false);
     m_builder->addFunctionCall("test_const_bool", Compiler::StaticType::Bool, { Compiler::StaticType::Bool }, { v });
 
-    auto code2 = m_builder->finalize();
+    auto code2 = m_builder->build();
 
     Script script1(&sprite, nullptr, nullptr);
     script1.setCode(code1);
@@ -3285,7 +3285,7 @@ TEST_F(LLVMCodeBuilderTest, Reporters)
 
     m_builder->addConstValue(-45.23);
 
-    auto code1 = m_builder->finalize();
+    auto code1 = m_builder->build();
 
     // Reporter 2
     createReporterBuilder(&sprite);
@@ -3293,27 +3293,27 @@ TEST_F(LLVMCodeBuilderTest, Reporters)
     CompilerValue *v = m_builder->addConstValue("test");
     m_builder->addFunctionCall("test_const_string", Compiler::StaticType::String, { Compiler::StaticType::String }, { v });
 
-    auto code2 = m_builder->finalize();
+    auto code2 = m_builder->build();
 
     // Reporter 3
     createReporterBuilder(&sprite);
     m_builder->addVariableValue(var.get());
 
-    auto code3 = m_builder->finalize();
+    auto code3 = m_builder->build();
 
     // Reporter 4
     createReporterBuilder(&sprite);
     int pointee;
     m_builder->addConstValue(&pointee);
 
-    auto code4 = m_builder->finalize();
+    auto code4 = m_builder->build();
 
     // Reporter 5
     createReporterBuilder(&sprite);
     v = m_builder->addConstValue(&pointee);
     m_builder->addFunctionCall("test_const_pointer", Compiler::StaticType::Pointer, { Compiler::StaticType::Pointer }, { v });
 
-    auto code5 = m_builder->finalize();
+    auto code5 = m_builder->build();
 
     auto runReporter = [&sprite](std::shared_ptr<ExecutableCode> code) {
         Script script(&sprite, nullptr, nullptr);
diff --git a/test/llvm/llvmtestutils.cpp b/test/llvm/llvmtestutils.cpp
index 2ace9069..b57a8f52 100644
--- a/test/llvm/llvmtestutils.cpp
+++ b/test/llvm/llvmtestutils.cpp
@@ -85,7 +85,7 @@ Value LLVMTestUtils::getOpResult(OpType type, bool rawArg, const Value &v)
         addOp(type, arg);
     }
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&m_target, nullptr, nullptr);
     script.setCode(code);
     Thread thread(&m_target, nullptr, &script);
@@ -113,7 +113,7 @@ Value LLVMTestUtils::getOpResult(OpType type, bool rawArgs, const Value &v1, con
         addOp(type, arg1, arg2);
     }
 
-    auto code = m_builder->finalize();
+    auto code = m_builder->build();
     Script script(&m_target, nullptr, nullptr);
     script.setCode(code);
     Thread thread(&m_target, nullptr, &script);
diff --git a/test/mocks/codebuildermock.h b/test/mocks/codebuildermock.h
index f3cf09ab..6ff635c1 100644
--- a/test/mocks/codebuildermock.h
+++ b/test/mocks/codebuildermock.h
@@ -8,7 +8,7 @@ using namespace libscratchcpp;
 class CodeBuilderMock : public ICodeBuilder
 {
     public:
-        MOCK_METHOD(std::shared_ptr<ExecutableCode>, finalize, (), (override));
+        MOCK_METHOD(std::shared_ptr<ExecutableCode>, build, (), (override));
         MOCK_METHOD(CompilerValue *, addFunctionCall, (const std::string &, Compiler::StaticType, const Compiler::ArgTypes &, const Compiler::Args &), (override));
         MOCK_METHOD(CompilerValue *, addTargetFunctionCall, (const std::string &, Compiler::StaticType, const Compiler::ArgTypes &, const Compiler::Args &), (override));
         MOCK_METHOD(CompilerValue *, addFunctionCallWithCtx, (const std::string &, Compiler::StaticType, const Compiler::ArgTypes &, const Compiler::Args &), (override));
diff --git a/test/scratch_classes/inputvalue_test.cpp b/test/scratch_classes/inputvalue_test.cpp
index 81014334..5ea5f59d 100644
--- a/test/scratch_classes/inputvalue_test.cpp
+++ b/test/scratch_classes/inputvalue_test.cpp
@@ -124,7 +124,7 @@ TEST(InputValueTest, Compile)
 
     auto block = std::make_shared<Block>("", "");
     EXPECT_CALL(builderFactory, create).WillOnce(Return(builder));
-    EXPECT_CALL(*builder, finalize);
+    EXPECT_CALL(*builder, build);
     compiler.compile(block.get());
     CompilerPrivate::builderFactory = nullptr;
 

From 0c65342044a6956864984122f73228b19bd46170 Mon Sep 17 00:00:00 2001
From: adazem009 <68537469+adazem009@users.noreply.github.com>
Date: Tue, 5 Aug 2025 13:11:56 +0200
Subject: [PATCH 79/79] Use LLVMTestUtils in LLVMCodeBuilder test

---
 test/llvm/llvmcodebuilder_test.cpp | 2587 ++++++++++++++--------------
 test/llvm/llvmtestutils.cpp        |   10 +
 test/llvm/llvmtestutils.h          |    2 +
 3 files changed, 1280 insertions(+), 1319 deletions(-)

diff --git a/test/llvm/llvmcodebuilder_test.cpp b/test/llvm/llvmcodebuilder_test.cpp
index 50163908..69a24e34 100644
--- a/test/llvm/llvmcodebuilder_test.cpp
+++ b/test/llvm/llvmcodebuilder_test.cpp
@@ -16,7 +16,7 @@
 #include <enginemock.h>
 #include <randomgeneratormock.h>
 
-#include "testfunctions.h"
+#include "llvmtestutils.h"
 
 using namespace libscratchcpp;
 
@@ -26,58 +26,7 @@ using ::testing::Eq;
 class LLVMCodeBuilderTest : public testing::Test
 {
     public:
-        void SetUp() override
-        {
-            test_function(nullptr, nullptr, nullptr, nullptr, nullptr); // force dependency
-        }
-
-        void createBuilder(Target *target, BlockPrototype *procedurePrototype, Compiler::CodeType codeType = Compiler::CodeType::Script)
-        {
-            if (m_contexts.find(target) == m_contexts.cend() || !target)
-                m_contexts[target] = std::make_shared<LLVMCompilerContext>(&m_engine, target);
-
-            m_contextList.push_back(m_contexts[target]);
-            m_builder = std::make_unique<LLVMCodeBuilder>(m_contexts[target].get(), procedurePrototype, codeType);
-        }
-
-        void createBuilder(Target *target, bool warp)
-        {
-            m_procedurePrototype = std::make_shared<BlockPrototype>("test");
-            m_procedurePrototype->setWarp(warp);
-            createBuilder(target, m_procedurePrototype.get());
-        }
-
-        void createReporterBuilder(Target *target) { createBuilder(target, nullptr, Compiler::CodeType::Reporter); }
-
-        void createPredicateBuilder(Target *target) { createBuilder(target, nullptr, Compiler::CodeType::HatPredicate); }
-
-        void createBuilder(bool warp) { createBuilder(nullptr, warp); }
-
-        CompilerValue *callConstFuncForType(ValueType type, CompilerValue *arg)
-        {
-            switch (type) {
-                case ValueType::Number:
-                    return m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }, { arg });
-
-                case ValueType::Bool:
-                    return m_builder->addFunctionCall("test_const_bool", Compiler::StaticType::Bool, { Compiler::StaticType::Bool }, { arg });
-
-                case ValueType::String:
-                    return m_builder->addFunctionCall("test_const_string", Compiler::StaticType::String, { Compiler::StaticType::String }, { arg });
-
-                default:
-                    EXPECT_TRUE(false);
-                    return nullptr;
-            }
-        }
-
-        std::unordered_map<Target *, std::shared_ptr<LLVMCompilerContext>> m_contexts;
-        std::vector<std::shared_ptr<LLVMCompilerContext>> m_contextList;
-        std::unique_ptr<LLVMCodeBuilder> m_builder;
-        std::shared_ptr<BlockPrototype> m_procedurePrototype;
-        EngineMock m_engine;
-        TargetMock m_target; // NOTE: isStage() is used for call expectations
-        RandomGeneratorMock m_rng;
+        LLVMTestUtils m_utils;
 };
 
 TEST_F(LLVMCodeBuilderTest, FunctionCalls)
@@ -85,62 +34,61 @@ TEST_F(LLVMCodeBuilderTest, FunctionCalls)
     static const std::vector<bool> warpList = { false, true };
 
     for (bool warp : warpList) {
-        createBuilder(warp);
+        LLVMCodeBuilder *builder = m_utils.createBuilder(warp);
 
-        m_builder->addFunctionCall("test_empty_function", Compiler::StaticType::Void, {}, {});
+        builder->addFunctionCall("test_empty_function", Compiler::StaticType::Void, {}, {});
 
-        CompilerValue *v = m_builder->addConstValue("test");
-        m_builder->addFunctionCallWithCtx("test_ctx_function", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+        CompilerValue *v = builder->addConstValue("test");
+        builder->addFunctionCallWithCtx("test_ctx_function", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-        m_builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
+        builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
 
-        v = m_builder->addTargetFunctionCall("test_function_no_args_ret", Compiler::StaticType::String, {}, {});
-        m_builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+        v = builder->addTargetFunctionCall("test_function_no_args_ret", Compiler::StaticType::String, {}, {});
+        builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-        v = m_builder->addConstValue("1");
-        v = m_builder->addTargetFunctionCall("test_function_1_arg_ret", Compiler::StaticType::String, { Compiler::StaticType::String }, { v });
-        CompilerValue *v1 = m_builder->addConstValue("2");
-        CompilerValue *v2 = m_builder->addConstValue("3");
-        m_builder
-            ->addTargetFunctionCall("test_function_3_args", Compiler::StaticType::Void, { Compiler::StaticType::String, Compiler::StaticType::String, Compiler::StaticType::String }, { v, v1, v2 });
+        v = builder->addConstValue("1");
+        v = builder->addTargetFunctionCall("test_function_1_arg_ret", Compiler::StaticType::String, { Compiler::StaticType::String }, { v });
+        CompilerValue *v1 = builder->addConstValue("2");
+        CompilerValue *v2 = builder->addConstValue("3");
+        builder->addTargetFunctionCall("test_function_3_args", Compiler::StaticType::Void, { Compiler::StaticType::String, Compiler::StaticType::String, Compiler::StaticType::String }, { v, v1, v2 });
 
-        v = m_builder->addConstValue("test");
-        v1 = m_builder->addConstValue("4");
-        v2 = m_builder->addConstValue("5");
-        v = m_builder->addTargetFunctionCall(
+        v = builder->addConstValue("test");
+        v1 = builder->addConstValue("4");
+        v2 = builder->addConstValue("5");
+        v = builder->addTargetFunctionCall(
             "test_function_3_args_ret",
             Compiler::StaticType::String,
             { Compiler::StaticType::String, Compiler::StaticType::String, Compiler::StaticType::String },
             { v, v1, v2 });
-        m_builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+        builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-        v = m_builder->addConstValue(123);
-        v = m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }, { v });
-        m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
+        v = builder->addConstValue(123);
+        v = builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }, { v });
+        builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
 
-        v = m_builder->addConstValue(true);
-        v = m_builder->addFunctionCall("test_const_bool", Compiler::StaticType::Bool, { Compiler::StaticType::Bool }, { v });
-        m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
+        v = builder->addConstValue(true);
+        v = builder->addFunctionCall("test_const_bool", Compiler::StaticType::Bool, { Compiler::StaticType::Bool }, { v });
+        builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
 
-        v = m_builder->addConstValue(321.5);
-        m_builder->addFunctionCall("test_print_unknown", Compiler::StaticType::Void, { Compiler::StaticType::Unknown }, { v });
-        v = m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }, { v });
-        m_builder->addFunctionCall("test_print_unknown", Compiler::StaticType::Void, { Compiler::StaticType::Unknown }, { v });
+        v = builder->addConstValue(321.5);
+        builder->addFunctionCall("test_print_unknown", Compiler::StaticType::Void, { Compiler::StaticType::Unknown }, { v });
+        v = builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }, { v });
+        builder->addFunctionCall("test_print_unknown", Compiler::StaticType::Void, { Compiler::StaticType::Unknown }, { v });
 
-        v = m_builder->addConstValue("test");
-        m_builder->addFunctionCall("test_print_unknown", Compiler::StaticType::Void, { Compiler::StaticType::Unknown }, { v });
-        v = m_builder->addFunctionCall("test_const_string", Compiler::StaticType::String, { Compiler::StaticType::String }, { v });
-        m_builder->addFunctionCall("test_print_unknown", Compiler::StaticType::Void, { Compiler::StaticType::Unknown }, { v });
+        v = builder->addConstValue("test");
+        builder->addFunctionCall("test_print_unknown", Compiler::StaticType::Void, { Compiler::StaticType::Unknown }, { v });
+        v = builder->addFunctionCall("test_const_string", Compiler::StaticType::String, { Compiler::StaticType::String }, { v });
+        builder->addFunctionCall("test_print_unknown", Compiler::StaticType::Void, { Compiler::StaticType::Unknown }, { v });
 
-        v = m_builder->addConstValue(true);
-        m_builder->addFunctionCall("test_print_unknown", Compiler::StaticType::Void, { Compiler::StaticType::Unknown }, { v });
-        v = m_builder->addFunctionCall("test_const_bool", Compiler::StaticType::Bool, { Compiler::StaticType::Bool }, { v });
-        m_builder->addFunctionCall("test_print_unknown", Compiler::StaticType::Void, { Compiler::StaticType::Unknown }, { v });
+        v = builder->addConstValue(true);
+        builder->addFunctionCall("test_print_unknown", Compiler::StaticType::Void, { Compiler::StaticType::Unknown }, { v });
+        v = builder->addFunctionCall("test_const_bool", Compiler::StaticType::Bool, { Compiler::StaticType::Bool }, { v });
+        builder->addFunctionCall("test_print_unknown", Compiler::StaticType::Void, { Compiler::StaticType::Unknown }, { v });
 
-        auto code = m_builder->build();
-        Script script(&m_target, nullptr, nullptr);
+        auto code = builder->build();
+        Script script(&m_utils.target(), nullptr, nullptr);
         script.setCode(code);
-        Thread thread(&m_target, nullptr, &script);
+        Thread thread(&m_utils.target(), nullptr, &script);
         auto ctx = code->createExecutionContext(&thread);
 
         std::stringstream s;
@@ -167,7 +115,7 @@ TEST_F(LLVMCodeBuilderTest, FunctionCalls)
             "true\n"
             "true\n";
 
-        EXPECT_CALL(m_target, isStage()).Times(7);
+        EXPECT_CALL(m_utils.target(), isStage()).Times(7);
         testing::internal::CaptureStdout();
         code->run(ctx.get());
         ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
@@ -177,27 +125,27 @@ TEST_F(LLVMCodeBuilderTest, FunctionCalls)
 
 TEST_F(LLVMCodeBuilderTest, FunctionCallsWithPointers)
 {
-    createBuilder(true);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(true);
 
     int var = 12;
-    CompilerValue *v = m_builder->addConstValue(&var);
-    v = m_builder->addTargetFunctionCall("test_function_1_ptr_arg_ret", Compiler::StaticType::Pointer, { Compiler::StaticType::Pointer }, { v });
+    CompilerValue *v = builder->addConstValue(&var);
+    v = builder->addTargetFunctionCall("test_function_1_ptr_arg_ret", Compiler::StaticType::Pointer, { Compiler::StaticType::Pointer }, { v });
 
-    m_builder->addFunctionCall("test_print_pointer", Compiler::StaticType::Void, { Compiler::StaticType::Pointer }, { v });
+    builder->addFunctionCall("test_print_pointer", Compiler::StaticType::Void, { Compiler::StaticType::Pointer }, { v });
 
-    auto code = m_builder->build();
-    Script script(&m_target, nullptr, nullptr);
+    auto code = builder->build();
+    Script script(&m_utils.target(), nullptr, nullptr);
     script.setCode(code);
-    Thread thread(&m_target, nullptr, &script);
+    Thread thread(&m_utils.target(), nullptr, &script);
     auto ctx = code->createExecutionContext(&thread);
 
     std::stringstream s;
-    s << &m_target;
+    s << &m_utils.target();
     std::string ptr = s.str();
 
     const std::string expected = "1_arg_ret 12\n" + ptr + "\n";
 
-    EXPECT_CALL(m_target, isStage());
+    EXPECT_CALL(m_utils.target(), isStage());
     testing::internal::CaptureStdout();
     code->run(ctx.get());
     ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
@@ -206,32 +154,32 @@ TEST_F(LLVMCodeBuilderTest, FunctionCallsWithPointers)
 
 TEST_F(LLVMCodeBuilderTest, ConstCasting)
 {
-    createBuilder(true);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(true);
 
-    CompilerValue *v = m_builder->addConstValue(5.2);
-    m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
-    v = m_builder->addConstValue("-24.156");
-    m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
+    CompilerValue *v = builder->addConstValue(5.2);
+    builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
+    v = builder->addConstValue("-24.156");
+    builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
 
-    v = m_builder->addConstValue(true);
-    m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
+    v = builder->addConstValue(true);
+    builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
 
-    v = m_builder->addConstValue(0);
-    m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
+    v = builder->addConstValue(0);
+    builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
 
-    v = m_builder->addConstValue("false");
-    m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
+    v = builder->addConstValue("false");
+    builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
 
-    v = m_builder->addConstValue("123");
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue("123");
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addConstValue("hello world");
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue("hello world");
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    auto code = m_builder->build();
-    Script script(&m_target, nullptr, nullptr);
+    auto code = builder->build();
+    Script script(&m_utils.target(), nullptr, nullptr);
     script.setCode(code);
-    Thread thread(&m_target, nullptr, &script);
+    Thread thread(&m_utils.target(), nullptr, &script);
     auto ctx = code->createExecutionContext(&thread);
 
     static const std::string expected =
@@ -250,77 +198,77 @@ TEST_F(LLVMCodeBuilderTest, ConstCasting)
 
 TEST_F(LLVMCodeBuilderTest, RawValueCasting)
 {
-    createBuilder(true);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(true);
 
     // Number -> number
-    CompilerValue *v = m_builder->addConstValue(5.2);
-    v = callConstFuncForType(ValueType::Number, v);
-    m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
+    CompilerValue *v = builder->addConstValue(5.2);
+    v = m_utils.callConstFuncForType(ValueType::Number, v);
+    builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
 
     // Number -> bool
-    v = m_builder->addConstValue(-24.156);
-    v = callConstFuncForType(ValueType::Number, v);
-    m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
+    v = builder->addConstValue(-24.156);
+    v = m_utils.callConstFuncForType(ValueType::Number, v);
+    builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
 
-    v = m_builder->addConstValue(0);
-    v = callConstFuncForType(ValueType::Number, v);
-    m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
+    v = builder->addConstValue(0);
+    v = m_utils.callConstFuncForType(ValueType::Number, v);
+    builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
 
     // Number -> string
-    v = m_builder->addConstValue(59.8);
-    v = callConstFuncForType(ValueType::Number, v);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue(59.8);
+    v = m_utils.callConstFuncForType(ValueType::Number, v);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
     // Bool -> number
-    v = m_builder->addConstValue(true);
-    v = callConstFuncForType(ValueType::Bool, v);
-    m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
+    v = builder->addConstValue(true);
+    v = m_utils.callConstFuncForType(ValueType::Bool, v);
+    builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
 
-    v = m_builder->addConstValue(false);
-    v = callConstFuncForType(ValueType::Bool, v);
-    m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
+    v = builder->addConstValue(false);
+    v = m_utils.callConstFuncForType(ValueType::Bool, v);
+    builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
 
     // Bool -> bool
-    v = m_builder->addConstValue(true);
-    v = callConstFuncForType(ValueType::Bool, v);
-    m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
+    v = builder->addConstValue(true);
+    v = m_utils.callConstFuncForType(ValueType::Bool, v);
+    builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
 
-    v = m_builder->addConstValue(false);
-    v = callConstFuncForType(ValueType::Bool, v);
-    m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
+    v = builder->addConstValue(false);
+    v = m_utils.callConstFuncForType(ValueType::Bool, v);
+    builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
 
     // Bool -> string
-    v = m_builder->addConstValue(true);
-    v = callConstFuncForType(ValueType::Bool, v);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue(true);
+    v = m_utils.callConstFuncForType(ValueType::Bool, v);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addConstValue(false);
-    v = callConstFuncForType(ValueType::Bool, v);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue(false);
+    v = m_utils.callConstFuncForType(ValueType::Bool, v);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
     // String -> number
-    v = m_builder->addConstValue("5.2");
-    v = callConstFuncForType(ValueType::String, v);
-    m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
+    v = builder->addConstValue("5.2");
+    v = m_utils.callConstFuncForType(ValueType::String, v);
+    builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
 
     // String -> bool
-    v = m_builder->addConstValue("abc");
-    v = callConstFuncForType(ValueType::String, v);
-    m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
+    v = builder->addConstValue("abc");
+    v = m_utils.callConstFuncForType(ValueType::String, v);
+    builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
 
-    v = m_builder->addConstValue("false");
-    v = callConstFuncForType(ValueType::String, v);
-    m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
+    v = builder->addConstValue("false");
+    v = m_utils.callConstFuncForType(ValueType::String, v);
+    builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
 
     // String -> string
-    v = m_builder->addConstValue("hello world");
-    v = callConstFuncForType(ValueType::String, v);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue("hello world");
+    v = m_utils.callConstFuncForType(ValueType::String, v);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    auto code = m_builder->build();
-    Script script(&m_target, nullptr, nullptr);
+    auto code = builder->build();
+    Script script(&m_utils.target(), nullptr, nullptr);
     script.setCode(code);
-    Thread thread(&m_target, nullptr, &script);
+    Thread thread(&m_utils.target(), nullptr, &script);
     auto ctx = code->createExecutionContext(&thread);
 
     static const std::string expected =
@@ -348,41 +296,41 @@ TEST_F(LLVMCodeBuilderTest, LocalVariables)
 {
     Stage stage;
     Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
+    sprite.setEngine(&m_utils.engine());
+    EXPECT_CALL(m_utils.engine(), stage()).WillRepeatedly(Return(&stage));
 
-    createBuilder(&sprite, true);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(&sprite, true);
 
-    CompilerLocalVariable *var1 = m_builder->createLocalVariable(Compiler::StaticType::Number);
-    CompilerLocalVariable *var2 = m_builder->createLocalVariable(Compiler::StaticType::Number);
-    CompilerLocalVariable *var3 = m_builder->createLocalVariable(Compiler::StaticType::Bool);
-    CompilerLocalVariable *var4 = m_builder->createLocalVariable(Compiler::StaticType::Bool);
+    CompilerLocalVariable *var1 = builder->createLocalVariable(Compiler::StaticType::Number);
+    CompilerLocalVariable *var2 = builder->createLocalVariable(Compiler::StaticType::Number);
+    CompilerLocalVariable *var3 = builder->createLocalVariable(Compiler::StaticType::Bool);
+    CompilerLocalVariable *var4 = builder->createLocalVariable(Compiler::StaticType::Bool);
 
-    CompilerValue *v = m_builder->addConstValue(5);
-    m_builder->createLocalVariableWrite(var1, v);
+    CompilerValue *v = builder->addConstValue(5);
+    builder->createLocalVariableWrite(var1, v);
 
-    v = m_builder->addConstValue(-23.5);
-    v = callConstFuncForType(ValueType::Number, v);
-    m_builder->createLocalVariableWrite(var2, v);
+    v = builder->addConstValue(-23.5);
+    v = m_utils.callConstFuncForType(ValueType::Number, v);
+    builder->createLocalVariableWrite(var2, v);
 
-    v = m_builder->addConstValue(5.2);
-    v = callConstFuncForType(ValueType::Number, v);
-    m_builder->createLocalVariableWrite(var2, v);
+    v = builder->addConstValue(5.2);
+    v = m_utils.callConstFuncForType(ValueType::Number, v);
+    builder->createLocalVariableWrite(var2, v);
 
-    v = m_builder->addConstValue(false);
-    m_builder->createLocalVariableWrite(var3, v);
+    v = builder->addConstValue(false);
+    builder->createLocalVariableWrite(var3, v);
 
-    v = m_builder->addConstValue(true);
-    m_builder->createLocalVariableWrite(var3, v);
+    v = builder->addConstValue(true);
+    builder->createLocalVariableWrite(var3, v);
 
-    v = m_builder->addConstValue(false);
-    v = callConstFuncForType(ValueType::Bool, v);
-    m_builder->createLocalVariableWrite(var4, v);
+    v = builder->addConstValue(false);
+    v = m_utils.callConstFuncForType(ValueType::Bool, v);
+    builder->createLocalVariableWrite(var4, v);
 
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { m_builder->addLocalVariableValue(var1) });
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { m_builder->addLocalVariableValue(var2) });
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { m_builder->addLocalVariableValue(var3) });
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { m_builder->addLocalVariableValue(var4) });
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { builder->addLocalVariableValue(var1) });
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { builder->addLocalVariableValue(var2) });
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { builder->addLocalVariableValue(var3) });
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { builder->addLocalVariableValue(var4) });
 
     static const std::string expected =
         "5\n"
@@ -390,7 +338,7 @@ TEST_F(LLVMCodeBuilderTest, LocalVariables)
         "true\n"
         "false\n";
 
-    auto code = m_builder->build();
+    auto code = builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     Thread thread(&sprite, nullptr, &script);
@@ -404,8 +352,8 @@ TEST_F(LLVMCodeBuilderTest, WriteVariable)
 {
     Stage stage;
     Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
+    sprite.setEngine(&m_utils.engine());
+    EXPECT_CALL(m_utils.engine(), stage()).WillRepeatedly(Return(&stage));
 
     auto globalVar1 = std::make_shared<Variable>("", "");
     auto globalVar2 = std::make_shared<Variable>("", "");
@@ -421,33 +369,33 @@ TEST_F(LLVMCodeBuilderTest, WriteVariable)
     sprite.addVariable(localVar2);
     sprite.addVariable(localVar3);
 
-    createBuilder(&sprite, true);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(&sprite, true);
 
-    CompilerValue *v = m_builder->addConstValue(5);
-    m_builder->createVariableWrite(globalVar1.get(), v);
+    CompilerValue *v = builder->addConstValue(5);
+    builder->createVariableWrite(globalVar1.get(), v);
 
-    v = m_builder->addConstValue(-23.5);
-    v = callConstFuncForType(ValueType::Number, v);
-    m_builder->createVariableWrite(globalVar2.get(), v);
+    v = builder->addConstValue(-23.5);
+    v = m_utils.callConstFuncForType(ValueType::Number, v);
+    builder->createVariableWrite(globalVar2.get(), v);
 
-    v = m_builder->addConstValue("test");
-    m_builder->createVariableWrite(globalVar3.get(), v);
+    v = builder->addConstValue("test");
+    builder->createVariableWrite(globalVar3.get(), v);
 
-    v = m_builder->addConstValue("abc");
-    m_builder->createVariableWrite(localVar1.get(), v);
+    v = builder->addConstValue("abc");
+    builder->createVariableWrite(localVar1.get(), v);
 
-    v = m_builder->addConstValue("hello world");
-    v = callConstFuncForType(ValueType::String, v);
-    m_builder->createVariableWrite(localVar1.get(), v);
+    v = builder->addConstValue("hello world");
+    v = m_utils.callConstFuncForType(ValueType::String, v);
+    builder->createVariableWrite(localVar1.get(), v);
 
-    v = m_builder->addConstValue(false);
-    m_builder->createVariableWrite(localVar2.get(), v);
+    v = builder->addConstValue(false);
+    builder->createVariableWrite(localVar2.get(), v);
 
-    v = m_builder->addConstValue(true);
-    v = callConstFuncForType(ValueType::Bool, v);
-    m_builder->createVariableWrite(localVar3.get(), v);
+    v = builder->addConstValue(true);
+    v = m_utils.callConstFuncForType(ValueType::Bool, v);
+    builder->createVariableWrite(localVar3.get(), v);
 
-    auto code = m_builder->build();
+    auto code = builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -467,63 +415,63 @@ TEST_F(LLVMCodeBuilderTest, Select)
 {
     Stage stage;
     Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
+    sprite.setEngine(&m_utils.engine());
+    EXPECT_CALL(m_utils.engine(), stage()).WillRepeatedly(Return(&stage));
 
-    createBuilder(&sprite, true);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(&sprite, true);
 
     // Number
-    CompilerValue *v = m_builder->addConstValue(true);
-    v = m_builder->createSelect(v, m_builder->addConstValue(5.8), m_builder->addConstValue(-17.42), Compiler::StaticType::Number);
-    m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
+    CompilerValue *v = builder->addConstValue(true);
+    v = builder->createSelect(v, builder->addConstValue(5.8), builder->addConstValue(-17.42), Compiler::StaticType::Number);
+    builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
 
-    v = m_builder->addConstValue(false);
-    v = m_builder->createSelect(v, m_builder->addConstValue(5.8), m_builder->addConstValue(-17.42), Compiler::StaticType::Number);
-    m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
+    v = builder->addConstValue(false);
+    v = builder->createSelect(v, builder->addConstValue(5.8), builder->addConstValue(-17.42), Compiler::StaticType::Number);
+    builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
 
     // Bool
-    v = m_builder->addConstValue(true);
-    v = m_builder->createSelect(v, m_builder->addConstValue(true), m_builder->addConstValue(false), Compiler::StaticType::Bool);
-    m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
+    v = builder->addConstValue(true);
+    v = builder->createSelect(v, builder->addConstValue(true), builder->addConstValue(false), Compiler::StaticType::Bool);
+    builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
 
-    v = m_builder->addConstValue(false);
-    v = m_builder->createSelect(v, m_builder->addConstValue(true), m_builder->addConstValue(false), Compiler::StaticType::Bool);
-    m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
+    v = builder->addConstValue(false);
+    v = builder->createSelect(v, builder->addConstValue(true), builder->addConstValue(false), Compiler::StaticType::Bool);
+    builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
 
     // String
-    v = m_builder->addConstValue(true);
-    v = m_builder->createSelect(v, m_builder->addConstValue("hello"), m_builder->addConstValue("world"), Compiler::StaticType::String);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue(true);
+    v = builder->createSelect(v, builder->addConstValue("hello"), builder->addConstValue("world"), Compiler::StaticType::String);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addConstValue(false);
-    v = m_builder->createSelect(v, m_builder->addConstValue("hello"), m_builder->addConstValue("world"), Compiler::StaticType::String);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue(false);
+    v = builder->createSelect(v, builder->addConstValue("hello"), builder->addConstValue("world"), Compiler::StaticType::String);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
     // Different types
-    v = m_builder->addConstValue(true);
-    v = m_builder->createSelect(v, m_builder->addConstValue("543"), m_builder->addConstValue("true"), Compiler::StaticType::Number);
-    m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
+    v = builder->addConstValue(true);
+    v = builder->createSelect(v, builder->addConstValue("543"), builder->addConstValue("true"), Compiler::StaticType::Number);
+    builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
 
-    v = m_builder->addConstValue(false);
-    v = m_builder->createSelect(v, m_builder->addConstValue("543"), m_builder->addConstValue("true"), Compiler::StaticType::Number);
-    m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
+    v = builder->addConstValue(false);
+    v = builder->createSelect(v, builder->addConstValue("543"), builder->addConstValue("true"), Compiler::StaticType::Number);
+    builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
 
-    v = m_builder->addConstValue(true);
-    v = m_builder->createSelect(v, m_builder->addConstValue(1), m_builder->addConstValue("false"), Compiler::StaticType::Bool);
-    m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
+    v = builder->addConstValue(true);
+    v = builder->createSelect(v, builder->addConstValue(1), builder->addConstValue("false"), Compiler::StaticType::Bool);
+    builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
 
-    v = m_builder->addConstValue(false);
-    v = m_builder->createSelect(v, m_builder->addConstValue(1), m_builder->addConstValue("false"), Compiler::StaticType::Bool);
-    m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
+    v = builder->addConstValue(false);
+    v = builder->createSelect(v, builder->addConstValue(1), builder->addConstValue("false"), Compiler::StaticType::Bool);
+    builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
 
     // Unknown types
-    v = m_builder->addConstValue(true);
-    v = m_builder->createSelect(v, m_builder->addConstValue("test"), m_builder->addConstValue(-456.2), Compiler::StaticType::Unknown);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue(true);
+    v = builder->createSelect(v, builder->addConstValue("test"), builder->addConstValue(-456.2), Compiler::StaticType::Unknown);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addConstValue(false);
-    v = m_builder->createSelect(v, m_builder->addConstValue("abc"), m_builder->addConstValue(true), Compiler::StaticType::Unknown);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue(false);
+    v = builder->createSelect(v, builder->addConstValue("abc"), builder->addConstValue(true), Compiler::StaticType::Unknown);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
     static const std::string expected =
         "5.8\n"
@@ -539,7 +487,7 @@ TEST_F(LLVMCodeBuilderTest, Select)
         "test\n"
         "true\n";
 
-    auto code = m_builder->build();
+    auto code = builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -554,8 +502,8 @@ TEST_F(LLVMCodeBuilderTest, ReadVariable)
 {
     Stage stage;
     Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
+    sprite.setEngine(&m_utils.engine());
+    EXPECT_CALL(m_utils.engine(), stage()).WillRepeatedly(Return(&stage));
 
     auto globalVar1 = std::make_shared<Variable>("", "", 87);
     auto globalVar2 = std::make_shared<Variable>("", "", 6.4);
@@ -571,25 +519,25 @@ TEST_F(LLVMCodeBuilderTest, ReadVariable)
     sprite.addVariable(localVar2);
     sprite.addVariable(localVar3);
 
-    createBuilder(&sprite, true);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(&sprite, true);
 
-    CompilerValue *v = m_builder->addVariableValue(globalVar1.get());
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    CompilerValue *v = builder->addVariableValue(globalVar1.get());
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addVariableValue(globalVar2.get());
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addVariableValue(globalVar2.get());
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addVariableValue(globalVar3.get());
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addVariableValue(globalVar3.get());
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addVariableValue(localVar1.get());
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addVariableValue(localVar1.get());
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addVariableValue(localVar2.get());
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addVariableValue(localVar2.get());
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addVariableValue(localVar3.get());
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addVariableValue(localVar3.get());
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
     std::string expected;
     expected += globalVar1->value().toString() + '\n';
@@ -599,7 +547,7 @@ TEST_F(LLVMCodeBuilderTest, ReadVariable)
     expected += localVar2->value().toString() + '\n';
     expected += localVar3->value().toString() + '\n';
 
-    auto code = m_builder->build();
+    auto code = builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -613,25 +561,25 @@ TEST_F(LLVMCodeBuilderTest, ReadVariable)
 TEST_F(LLVMCodeBuilderTest, SyncVariablesBeforeCallingFunction)
 {
     Sprite sprite;
-    sprite.setEngine(&m_engine);
+    sprite.setEngine(&m_utils.engine());
 
     auto var = std::make_shared<Variable>("", "");
     sprite.addVariable(var);
 
-    createBuilder(&sprite, true);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(&sprite, true);
 
-    CompilerValue *v = m_builder->addConstValue("abc");
-    m_builder->createVariableWrite(var.get(), v);
+    CompilerValue *v = builder->addConstValue("abc");
+    builder->createVariableWrite(var.get(), v);
 
-    v = m_builder->addConstValue(123);
-    m_builder->createVariableWrite(var.get(), v);
+    v = builder->addConstValue(123);
+    builder->createVariableWrite(var.get(), v);
 
-    m_builder->addTargetFunctionCall("test_print_first_local_variable", Compiler::StaticType::Void, {}, {});
+    builder->addTargetFunctionCall("test_print_first_local_variable", Compiler::StaticType::Void, {}, {});
 
-    v = m_builder->addConstValue(456);
-    m_builder->createVariableWrite(var.get(), v);
+    v = builder->addConstValue(456);
+    builder->createVariableWrite(var.get(), v);
 
-    auto code = m_builder->build();
+    auto code = builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
 
@@ -647,35 +595,35 @@ TEST_F(LLVMCodeBuilderTest, CastNonRawValueToUnknownType)
 {
     Stage stage;
     Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
+    sprite.setEngine(&m_utils.engine());
+    EXPECT_CALL(m_utils.engine(), stage()).WillRepeatedly(Return(&stage));
 
     auto var = std::make_shared<Variable>("", "", 87);
     stage.addVariable(var);
 
-    createBuilder(&sprite, true);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(&sprite, true);
 
     // Unknown type
-    CompilerValue *v = m_builder->addVariableValue(var.get());
-    m_builder->addFunctionCall("test_print_unknown", Compiler::StaticType::Void, { Compiler::StaticType::Unknown }, { v });
+    CompilerValue *v = builder->addVariableValue(var.get());
+    builder->addFunctionCall("test_print_unknown", Compiler::StaticType::Void, { Compiler::StaticType::Unknown }, { v });
 
     // Number
-    v = m_builder->addConstValue(23.5);
-    m_builder->createVariableWrite(var.get(), v);
-    v = m_builder->addVariableValue(var.get());
-    m_builder->addFunctionCall("test_print_unknown", Compiler::StaticType::Void, { Compiler::StaticType::Unknown }, { v });
+    v = builder->addConstValue(23.5);
+    builder->createVariableWrite(var.get(), v);
+    v = builder->addVariableValue(var.get());
+    builder->addFunctionCall("test_print_unknown", Compiler::StaticType::Void, { Compiler::StaticType::Unknown }, { v });
 
     // String
-    v = m_builder->addConstValue("Hello world");
-    m_builder->createVariableWrite(var.get(), v);
-    v = m_builder->addVariableValue(var.get());
-    m_builder->addFunctionCall("test_print_unknown", Compiler::StaticType::Void, { Compiler::StaticType::Unknown }, { v });
+    v = builder->addConstValue("Hello world");
+    builder->createVariableWrite(var.get(), v);
+    v = builder->addVariableValue(var.get());
+    builder->addFunctionCall("test_print_unknown", Compiler::StaticType::Void, { Compiler::StaticType::Unknown }, { v });
 
     // Bool
-    v = m_builder->addConstValue(true);
-    m_builder->createVariableWrite(var.get(), v);
-    v = m_builder->addVariableValue(var.get());
-    m_builder->addFunctionCall("test_print_unknown", Compiler::StaticType::Void, { Compiler::StaticType::Unknown }, { v });
+    v = builder->addConstValue(true);
+    builder->createVariableWrite(var.get(), v);
+    v = builder->addVariableValue(var.get());
+    builder->addFunctionCall("test_print_unknown", Compiler::StaticType::Void, { Compiler::StaticType::Unknown }, { v });
 
     std::string expected;
     expected += var->value().toString() + '\n';
@@ -683,7 +631,7 @@ TEST_F(LLVMCodeBuilderTest, CastNonRawValueToUnknownType)
     expected += "Hello world\n";
     expected += "true\n";
 
-    auto code = m_builder->build();
+    auto code = builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     Thread thread(&sprite, nullptr, &script);
@@ -697,8 +645,8 @@ TEST_F(LLVMCodeBuilderTest, ClearList)
 {
     Stage stage;
     Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
+    sprite.setEngine(&m_utils.engine());
+    EXPECT_CALL(m_utils.engine(), stage()).WillRepeatedly(Return(&stage));
 
     std::unordered_map<List *, std::string> strings;
 
@@ -746,14 +694,14 @@ TEST_F(LLVMCodeBuilderTest, ClearList)
     localList3->append(false);
     strings[localList3.get()] = localList3->toString();
 
-    createBuilder(&sprite, true);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(&sprite, true);
 
-    m_builder->createListClear(globalList1.get());
-    m_builder->createListClear(globalList3.get());
-    m_builder->createListClear(localList1.get());
-    m_builder->createListClear(localList2.get());
+    builder->createListClear(globalList1.get());
+    builder->createListClear(globalList3.get());
+    builder->createListClear(localList1.get());
+    builder->createListClear(localList2.get());
 
-    auto code = m_builder->build();
+    auto code = builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -774,8 +722,8 @@ TEST_F(LLVMCodeBuilderTest, RemoveFromList)
 {
     Stage stage;
     Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
+    sprite.setEngine(&m_utils.engine());
+    EXPECT_CALL(m_utils.engine(), stage()).WillRepeatedly(Return(&stage));
 
     std::unordered_map<List *, std::string> strings;
 
@@ -795,27 +743,27 @@ TEST_F(LLVMCodeBuilderTest, RemoveFromList)
     localList->append("sit");
     strings[localList.get()] = localList->toString();
 
-    createBuilder(&sprite, true);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(&sprite, true);
 
-    CompilerValue *v = m_builder->addConstValue(1);
-    m_builder->createListRemove(globalList.get(), v);
+    CompilerValue *v = builder->addConstValue(1);
+    builder->createListRemove(globalList.get(), v);
 
-    v = m_builder->addConstValue(-1);
-    m_builder->createListRemove(globalList.get(), v);
+    v = builder->addConstValue(-1);
+    builder->createListRemove(globalList.get(), v);
 
-    v = m_builder->addConstValue(3);
-    m_builder->createListRemove(globalList.get(), v);
+    v = builder->addConstValue(3);
+    builder->createListRemove(globalList.get(), v);
 
-    v = m_builder->addConstValue(3);
-    m_builder->createListRemove(localList.get(), v);
+    v = builder->addConstValue(3);
+    builder->createListRemove(localList.get(), v);
 
-    v = m_builder->addConstValue(-1);
-    m_builder->createListRemove(localList.get(), v);
+    v = builder->addConstValue(-1);
+    builder->createListRemove(localList.get(), v);
 
-    v = m_builder->addConstValue(4);
-    m_builder->createListRemove(localList.get(), v);
+    v = builder->addConstValue(4);
+    builder->createListRemove(localList.get(), v);
 
-    auto code = m_builder->build();
+    auto code = builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -831,8 +779,8 @@ TEST_F(LLVMCodeBuilderTest, AppendToList)
 {
     Stage stage;
     Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
+    sprite.setEngine(&m_utils.engine());
+    EXPECT_CALL(m_utils.engine(), stage()).WillRepeatedly(Return(&stage));
 
     std::unordered_map<List *, std::string> strings;
 
@@ -852,29 +800,29 @@ TEST_F(LLVMCodeBuilderTest, AppendToList)
     localList->append("sit");
     strings[localList.get()] = localList->toString();
 
-    createBuilder(&sprite, true);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(&sprite, true);
 
-    CompilerValue *v = m_builder->addConstValue(1);
-    m_builder->createListAppend(globalList.get(), v);
+    CompilerValue *v = builder->addConstValue(1);
+    builder->createListAppend(globalList.get(), v);
 
-    v = m_builder->addConstValue("test");
-    m_builder->createListAppend(globalList.get(), v);
+    v = builder->addConstValue("test");
+    builder->createListAppend(globalList.get(), v);
 
-    v = m_builder->addConstValue(3);
-    m_builder->createListAppend(localList.get(), v);
+    v = builder->addConstValue(3);
+    builder->createListAppend(localList.get(), v);
 
-    m_builder->createListClear(localList.get());
+    builder->createListClear(localList.get());
 
-    v = m_builder->addConstValue(true);
-    m_builder->createListAppend(localList.get(), v);
+    v = builder->addConstValue(true);
+    builder->createListAppend(localList.get(), v);
 
-    v = m_builder->addConstValue(false);
-    m_builder->createListAppend(localList.get(), v);
+    v = builder->addConstValue(false);
+    builder->createListAppend(localList.get(), v);
 
-    v = m_builder->addConstValue("hello world");
-    m_builder->createListAppend(localList.get(), v);
+    v = builder->addConstValue("hello world");
+    builder->createListAppend(localList.get(), v);
 
-    auto code = m_builder->build();
+    auto code = builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -890,8 +838,8 @@ TEST_F(LLVMCodeBuilderTest, InsertToList)
 {
     Stage stage;
     Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
+    sprite.setEngine(&m_utils.engine());
+    EXPECT_CALL(m_utils.engine(), stage()).WillRepeatedly(Return(&stage));
 
     std::unordered_map<List *, std::string> strings;
 
@@ -911,47 +859,47 @@ TEST_F(LLVMCodeBuilderTest, InsertToList)
     localList->append("sit");
     strings[localList.get()] = localList->toString();
 
-    createBuilder(&sprite, true);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(&sprite, true);
 
-    CompilerValue *v1 = m_builder->addConstValue(2);
-    CompilerValue *v2 = m_builder->addConstValue(1);
-    m_builder->createListInsert(globalList.get(), v1, v2);
+    CompilerValue *v1 = builder->addConstValue(2);
+    CompilerValue *v2 = builder->addConstValue(1);
+    builder->createListInsert(globalList.get(), v1, v2);
 
-    v1 = m_builder->addConstValue(3);
-    v2 = m_builder->addConstValue("test");
-    m_builder->createListInsert(globalList.get(), v1, v2);
+    v1 = builder->addConstValue(3);
+    v2 = builder->addConstValue("test");
+    builder->createListInsert(globalList.get(), v1, v2);
 
-    v1 = m_builder->addConstValue(0);
-    v2 = m_builder->addConstValue(3);
-    m_builder->createListInsert(localList.get(), v1, v2);
+    v1 = builder->addConstValue(0);
+    v2 = builder->addConstValue(3);
+    builder->createListInsert(localList.get(), v1, v2);
 
-    m_builder->createListClear(localList.get());
+    builder->createListClear(localList.get());
 
-    v1 = m_builder->addConstValue(0);
-    v2 = m_builder->addConstValue(true);
-    m_builder->createListInsert(localList.get(), v1, v2);
+    v1 = builder->addConstValue(0);
+    v2 = builder->addConstValue(true);
+    builder->createListInsert(localList.get(), v1, v2);
 
-    v1 = m_builder->addConstValue(0);
-    v2 = m_builder->addConstValue(false);
-    m_builder->createListInsert(localList.get(), v1, v2);
+    v1 = builder->addConstValue(0);
+    v2 = builder->addConstValue(false);
+    builder->createListInsert(localList.get(), v1, v2);
 
-    v1 = m_builder->addConstValue(1);
-    v2 = m_builder->addConstValue("hello world");
-    m_builder->createListInsert(localList.get(), v1, v2);
+    v1 = builder->addConstValue(1);
+    v2 = builder->addConstValue("hello world");
+    builder->createListInsert(localList.get(), v1, v2);
 
-    v1 = m_builder->addConstValue(3);
-    v2 = m_builder->addConstValue("test");
-    m_builder->createListInsert(localList.get(), v1, v2);
+    v1 = builder->addConstValue(3);
+    v2 = builder->addConstValue("test");
+    builder->createListInsert(localList.get(), v1, v2);
 
-    v1 = m_builder->addConstValue(-1);
-    v2 = m_builder->addConstValue(123);
-    m_builder->createListInsert(localList.get(), v1, v2);
+    v1 = builder->addConstValue(-1);
+    v2 = builder->addConstValue(123);
+    builder->createListInsert(localList.get(), v1, v2);
 
-    v1 = m_builder->addConstValue(6);
-    v2 = m_builder->addConstValue(123);
-    m_builder->createListInsert(localList.get(), v1, v2);
+    v1 = builder->addConstValue(6);
+    v2 = builder->addConstValue(123);
+    builder->createListInsert(localList.get(), v1, v2);
 
-    auto code = m_builder->build();
+    auto code = builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -967,8 +915,8 @@ TEST_F(LLVMCodeBuilderTest, ListReplace)
 {
     Stage stage;
     Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
+    sprite.setEngine(&m_utils.engine());
+    EXPECT_CALL(m_utils.engine(), stage()).WillRepeatedly(Return(&stage));
 
     std::unordered_map<List *, std::string> strings;
 
@@ -988,37 +936,37 @@ TEST_F(LLVMCodeBuilderTest, ListReplace)
     localList->append("sit");
     strings[localList.get()] = localList->toString();
 
-    createBuilder(&sprite, true);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(&sprite, true);
 
-    CompilerValue *v1 = m_builder->addConstValue(2);
-    CompilerValue *v2 = m_builder->addConstValue(1);
-    m_builder->createListReplace(globalList.get(), v1, v2);
+    CompilerValue *v1 = builder->addConstValue(2);
+    CompilerValue *v2 = builder->addConstValue(1);
+    builder->createListReplace(globalList.get(), v1, v2);
 
-    v1 = m_builder->addConstValue(1);
-    v2 = m_builder->addConstValue("test");
-    m_builder->createListReplace(globalList.get(), v1, v2);
+    v1 = builder->addConstValue(1);
+    v2 = builder->addConstValue("test");
+    builder->createListReplace(globalList.get(), v1, v2);
 
-    v1 = m_builder->addConstValue(0);
-    v2 = m_builder->addConstValue(3);
-    m_builder->createListReplace(localList.get(), v1, v2);
+    v1 = builder->addConstValue(0);
+    v2 = builder->addConstValue(3);
+    builder->createListReplace(localList.get(), v1, v2);
 
-    v1 = m_builder->addConstValue(2);
-    v2 = m_builder->addConstValue(true);
-    m_builder->createListReplace(localList.get(), v1, v2);
+    v1 = builder->addConstValue(2);
+    v2 = builder->addConstValue(true);
+    builder->createListReplace(localList.get(), v1, v2);
 
-    v1 = m_builder->addConstValue(3);
-    v2 = m_builder->addConstValue("hello world");
-    m_builder->createListReplace(localList.get(), v1, v2);
+    v1 = builder->addConstValue(3);
+    v2 = builder->addConstValue("hello world");
+    builder->createListReplace(localList.get(), v1, v2);
 
-    v1 = m_builder->addConstValue(-1);
-    v2 = m_builder->addConstValue(123);
-    m_builder->createListReplace(localList.get(), v1, v2);
+    v1 = builder->addConstValue(-1);
+    v2 = builder->addConstValue(123);
+    builder->createListReplace(localList.get(), v1, v2);
 
-    v1 = m_builder->addConstValue(5);
-    v2 = m_builder->addConstValue(123);
-    m_builder->createListReplace(localList.get(), v1, v2);
+    v1 = builder->addConstValue(5);
+    v2 = builder->addConstValue(123);
+    builder->createListReplace(localList.get(), v1, v2);
 
-    auto code = m_builder->build();
+    auto code = builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -1034,8 +982,8 @@ TEST_F(LLVMCodeBuilderTest, GetListContents)
 {
     Stage stage;
     Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
+    sprite.setEngine(&m_utils.engine());
+    EXPECT_CALL(m_utils.engine(), stage()).WillRepeatedly(Return(&stage));
 
     std::unordered_map<List *, std::string> strings;
 
@@ -1055,19 +1003,19 @@ TEST_F(LLVMCodeBuilderTest, GetListContents)
     localList->append("sit");
     strings[localList.get()] = localList->toString();
 
-    createBuilder(&sprite, true);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(&sprite, true);
 
-    CompilerValue *v = m_builder->addListContents(globalList.get());
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    CompilerValue *v = builder->addListContents(globalList.get());
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addListContents(localList.get());
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addListContents(localList.get());
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
     static const std::string expected =
         "123\n"
         "Lorem ipsum dolor sit\n";
 
-    auto code = m_builder->build();
+    auto code = builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -1085,8 +1033,8 @@ TEST_F(LLVMCodeBuilderTest, GetListItem)
 {
     Stage stage;
     Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
+    sprite.setEngine(&m_utils.engine());
+    EXPECT_CALL(m_utils.engine(), stage()).WillRepeatedly(Return(&stage));
 
     auto globalList = std::make_shared<List>("", "");
     stage.addList(globalList);
@@ -1115,67 +1063,67 @@ TEST_F(LLVMCodeBuilderTest, GetListItem)
     localList3->append(true);
     localList3->append(false);
 
-    createBuilder(&sprite, true);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(&sprite, true);
 
     // Global
-    CompilerValue *v = m_builder->addConstValue(2);
-    v = m_builder->addListItem(globalList.get(), v);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    CompilerValue *v = builder->addConstValue(2);
+    v = builder->addListItem(globalList.get(), v);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    CompilerValue *v1 = m_builder->addConstValue(1);
-    CompilerValue *v2 = m_builder->addConstValue("test");
-    m_builder->createListReplace(globalList.get(), v1, v2);
+    CompilerValue *v1 = builder->addConstValue(1);
+    CompilerValue *v2 = builder->addConstValue("test");
+    builder->createListReplace(globalList.get(), v1, v2);
 
-    v = m_builder->addConstValue(0);
-    v = m_builder->addListItem(globalList.get(), v);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue(0);
+    v = builder->addListItem(globalList.get(), v);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addConstValue(-1);
-    v = m_builder->addListItem(globalList.get(), v);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue(-1);
+    v = builder->addListItem(globalList.get(), v);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addConstValue(3);
-    v = m_builder->addListItem(globalList.get(), v);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue(3);
+    v = builder->addListItem(globalList.get(), v);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
     // Local 1
-    v = m_builder->addConstValue(0);
-    v = m_builder->addListItem(localList1.get(), v);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue(0);
+    v = builder->addListItem(localList1.get(), v);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addConstValue(2);
-    v = m_builder->addListItem(localList1.get(), v);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue(2);
+    v = builder->addListItem(localList1.get(), v);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addConstValue(3);
-    v = m_builder->addListItem(localList1.get(), v);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue(3);
+    v = builder->addListItem(localList1.get(), v);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addConstValue(-1);
-    v = m_builder->addListItem(localList1.get(), v);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue(-1);
+    v = builder->addListItem(localList1.get(), v);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addConstValue(4);
-    v = m_builder->addListItem(localList1.get(), v);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue(4);
+    v = builder->addListItem(localList1.get(), v);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
     // Local 2
-    v = m_builder->addConstValue(-1);
-    v = m_builder->addListItem(localList2.get(), v);
-    m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
+    v = builder->addConstValue(-1);
+    v = builder->addListItem(localList2.get(), v);
+    builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
 
-    v = m_builder->addConstValue(2);
-    v = m_builder->addListItem(localList2.get(), v);
-    m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
+    v = builder->addConstValue(2);
+    v = builder->addListItem(localList2.get(), v);
+    builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
 
     // Local 3
-    v = m_builder->addConstValue(-1);
-    v = m_builder->addListItem(localList3.get(), v);
-    m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
+    v = builder->addConstValue(-1);
+    v = builder->addListItem(localList3.get(), v);
+    builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
 
-    v = m_builder->addConstValue(2);
-    v = m_builder->addListItem(localList3.get(), v);
-    m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
+    v = builder->addConstValue(2);
+    v = builder->addListItem(localList3.get(), v);
+    builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
 
     static const std::string expected =
         "3\n"
@@ -1192,7 +1140,7 @@ TEST_F(LLVMCodeBuilderTest, GetListItem)
         "0\n"
         "0\n";
 
-    auto code = m_builder->build();
+    auto code = builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -1212,8 +1160,8 @@ TEST_F(LLVMCodeBuilderTest, GetListSize)
 {
     Stage stage;
     Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
+    sprite.setEngine(&m_utils.engine());
+    EXPECT_CALL(m_utils.engine(), stage()).WillRepeatedly(Return(&stage));
 
     auto globalList = std::make_shared<List>("", "");
     stage.addList(globalList);
@@ -1230,19 +1178,19 @@ TEST_F(LLVMCodeBuilderTest, GetListSize)
     localList->append("dolor");
     localList->append("sit");
 
-    createBuilder(&sprite, true);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(&sprite, true);
 
-    CompilerValue *v = m_builder->addListSize(globalList.get());
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    CompilerValue *v = builder->addListSize(globalList.get());
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addListSize(localList.get());
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addListSize(localList.get());
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
     static const std::string expected =
         "3\n"
         "4\n";
 
-    auto code = m_builder->build();
+    auto code = builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -1260,8 +1208,8 @@ TEST_F(LLVMCodeBuilderTest, GetListItemIndex)
 {
     Stage stage;
     Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
+    sprite.setEngine(&m_utils.engine());
+    EXPECT_CALL(m_utils.engine(), stage()).WillRepeatedly(Return(&stage));
 
     auto globalList = std::make_shared<List>("", "");
     stage.addList(globalList);
@@ -1278,51 +1226,51 @@ TEST_F(LLVMCodeBuilderTest, GetListItemIndex)
     localList->append("dolor");
     localList->append("sit");
 
-    createBuilder(&sprite, true);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(&sprite, true);
 
-    CompilerValue *v = m_builder->addConstValue(2);
-    v = m_builder->addListItemIndex(globalList.get(), v);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    CompilerValue *v = builder->addConstValue(2);
+    v = builder->addListItemIndex(globalList.get(), v);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addConstValue(1);
-    v = m_builder->addListItemIndex(globalList.get(), v);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue(1);
+    v = builder->addListItemIndex(globalList.get(), v);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addConstValue(0);
-    v = m_builder->addListItemIndex(globalList.get(), v);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue(0);
+    v = builder->addListItemIndex(globalList.get(), v);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    CompilerValue *v1 = m_builder->addConstValue(1);
-    CompilerValue *v2 = m_builder->addConstValue("test");
-    m_builder->createListReplace(globalList.get(), v1, v2);
+    CompilerValue *v1 = builder->addConstValue(1);
+    CompilerValue *v2 = builder->addConstValue("test");
+    builder->createListReplace(globalList.get(), v1, v2);
 
-    v = m_builder->addConstValue(2);
-    v = m_builder->addListItemIndex(globalList.get(), v);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue(2);
+    v = builder->addListItemIndex(globalList.get(), v);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addConstValue(1);
-    v = m_builder->addListItemIndex(globalList.get(), v);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue(1);
+    v = builder->addListItemIndex(globalList.get(), v);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addConstValue("test");
-    v = m_builder->addListItemIndex(globalList.get(), v);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue("test");
+    v = builder->addListItemIndex(globalList.get(), v);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addConstValue("abc");
-    v = m_builder->addListItemIndex(globalList.get(), v);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue("abc");
+    v = builder->addListItemIndex(globalList.get(), v);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addConstValue("doLor");
-    v = m_builder->addListItemIndex(localList.get(), v);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue("doLor");
+    v = builder->addListItemIndex(localList.get(), v);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addConstValue(true);
-    v = m_builder->addListItemIndex(localList.get(), v);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue(true);
+    v = builder->addListItemIndex(localList.get(), v);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addConstValue("site");
-    v = m_builder->addListItemIndex(localList.get(), v);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue("site");
+    v = builder->addListItemIndex(localList.get(), v);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
     static const std::string expected =
         "1\n"
@@ -1336,7 +1284,7 @@ TEST_F(LLVMCodeBuilderTest, GetListItemIndex)
         "-1\n"
         "-1\n";
 
-    auto code = m_builder->build();
+    auto code = builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -1354,8 +1302,8 @@ TEST_F(LLVMCodeBuilderTest, ListContainsItem)
 {
     Stage stage;
     Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
+    sprite.setEngine(&m_utils.engine());
+    EXPECT_CALL(m_utils.engine(), stage()).WillRepeatedly(Return(&stage));
 
     auto globalList = std::make_shared<List>("", "");
     stage.addList(globalList);
@@ -1372,51 +1320,51 @@ TEST_F(LLVMCodeBuilderTest, ListContainsItem)
     localList->append("dolor");
     localList->append("sit");
 
-    createBuilder(&sprite, true);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(&sprite, true);
 
-    CompilerValue *v = m_builder->addConstValue(2);
-    v = m_builder->addListContains(globalList.get(), v);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    CompilerValue *v = builder->addConstValue(2);
+    v = builder->addListContains(globalList.get(), v);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addConstValue(1);
-    v = m_builder->addListContains(globalList.get(), v);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue(1);
+    v = builder->addListContains(globalList.get(), v);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addConstValue(0);
-    v = m_builder->addListContains(globalList.get(), v);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue(0);
+    v = builder->addListContains(globalList.get(), v);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    CompilerValue *v1 = m_builder->addConstValue(1);
-    CompilerValue *v2 = m_builder->addConstValue("test");
-    m_builder->createListReplace(globalList.get(), v1, v2);
+    CompilerValue *v1 = builder->addConstValue(1);
+    CompilerValue *v2 = builder->addConstValue("test");
+    builder->createListReplace(globalList.get(), v1, v2);
 
-    v = m_builder->addConstValue(2);
-    v = m_builder->addListContains(globalList.get(), v);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue(2);
+    v = builder->addListContains(globalList.get(), v);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addConstValue(1);
-    v = m_builder->addListContains(globalList.get(), v);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue(1);
+    v = builder->addListContains(globalList.get(), v);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addConstValue("test");
-    v = m_builder->addListContains(globalList.get(), v);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue("test");
+    v = builder->addListContains(globalList.get(), v);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addConstValue("abc");
-    v = m_builder->addListContains(globalList.get(), v);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue("abc");
+    v = builder->addListContains(globalList.get(), v);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addConstValue("doLor");
-    v = m_builder->addListContains(localList.get(), v);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue("doLor");
+    v = builder->addListContains(localList.get(), v);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addConstValue(true);
-    v = m_builder->addListContains(localList.get(), v);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue(true);
+    v = builder->addListContains(localList.get(), v);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addConstValue("site");
-    v = m_builder->addListContains(localList.get(), v);
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue("site");
+    v = builder->addListContains(localList.get(), v);
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
     static const std::string expected =
         "true\n"
@@ -1430,7 +1378,7 @@ TEST_F(LLVMCodeBuilderTest, ListContainsItem)
         "false\n"
         "false\n";
 
-    auto code = m_builder->build();
+    auto code = builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -1446,40 +1394,41 @@ TEST_F(LLVMCodeBuilderTest, ListContainsItem)
 
 TEST_F(LLVMCodeBuilderTest, Yield)
 {
-    auto build = [this]() {
-        m_builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
+    LLVMCodeBuilder *builder;
+
+    auto build = [this, &builder]() {
+        builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
 
-        CompilerValue *v = m_builder->addTargetFunctionCall("test_function_no_args_ret", Compiler::StaticType::String, {}, {});
-        m_builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+        CompilerValue *v = builder->addTargetFunctionCall("test_function_no_args_ret", Compiler::StaticType::String, {}, {});
+        builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-        m_builder->yield();
+        builder->yield();
 
-        v = m_builder->addConstValue("1");
-        v = m_builder->addTargetFunctionCall("test_function_1_arg_ret", Compiler::StaticType::String, { Compiler::StaticType::String }, { v });
-        CompilerValue *v1 = m_builder->addConstValue("2");
-        CompilerValue *v2 = m_builder->addConstValue(3);
-        m_builder
-            ->addTargetFunctionCall("test_function_3_args", Compiler::StaticType::Void, { Compiler::StaticType::String, Compiler::StaticType::String, Compiler::StaticType::String }, { v, v1, v2 });
+        v = builder->addConstValue("1");
+        v = builder->addTargetFunctionCall("test_function_1_arg_ret", Compiler::StaticType::String, { Compiler::StaticType::String }, { v });
+        CompilerValue *v1 = builder->addConstValue("2");
+        CompilerValue *v2 = builder->addConstValue(3);
+        builder->addTargetFunctionCall("test_function_3_args", Compiler::StaticType::Void, { Compiler::StaticType::String, Compiler::StaticType::String, Compiler::StaticType::String }, { v, v1, v2 });
 
-        v = m_builder->addConstValue("test");
-        v1 = m_builder->addConstValue("4");
-        v2 = m_builder->addConstValue("5");
-        v = m_builder->addTargetFunctionCall(
+        v = builder->addConstValue("test");
+        v1 = builder->addConstValue("4");
+        v2 = builder->addConstValue("5");
+        v = builder->addTargetFunctionCall(
             "test_function_3_args_ret",
             Compiler::StaticType::String,
             { Compiler::StaticType::String, Compiler::StaticType::String, Compiler::StaticType::String },
             { v, v1, v2 });
-        m_builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+        builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
     };
 
     // Without warp
-    createBuilder(false);
+    builder = m_utils.createBuilder(false);
     build();
 
-    auto code = m_builder->build();
-    Script script(&m_target, nullptr, nullptr);
+    auto code = builder->build();
+    Script script(&m_utils.target(), nullptr, nullptr);
     script.setCode(code);
-    Thread thread(&m_target, nullptr, &script);
+    Thread thread(&m_utils.target(), nullptr, &script);
     auto ctx = code->createExecutionContext(&thread);
 
     static const std::string expected1 =
@@ -1487,7 +1436,7 @@ TEST_F(LLVMCodeBuilderTest, Yield)
         "no_args_ret\n"
         "1_arg no_args_output\n";
 
-    EXPECT_CALL(m_target, isStage()).Times(3);
+    EXPECT_CALL(m_utils.target(), isStage()).Times(3);
     testing::internal::CaptureStdout();
     code->run(ctx.get());
     ASSERT_EQ(testing::internal::GetCapturedStdout(), expected1);
@@ -1499,14 +1448,14 @@ TEST_F(LLVMCodeBuilderTest, Yield)
         "3_args test 4 5\n"
         "1_arg 3_args_output\n";
 
-    EXPECT_CALL(m_target, isStage()).Times(4);
+    EXPECT_CALL(m_utils.target(), isStage()).Times(4);
     testing::internal::CaptureStdout();
     code->run(ctx.get());
     ASSERT_EQ(testing::internal::GetCapturedStdout(), expected2);
     ASSERT_TRUE(code->isFinished(ctx.get()));
 
     // Terminate unfinished coroutine
-    EXPECT_CALL(m_target, isStage()).Times(3);
+    EXPECT_CALL(m_utils.target(), isStage()).Times(3);
     testing::internal::CaptureStdout();
     code->reset(ctx.get());
     code->run(ctx.get());
@@ -1517,7 +1466,7 @@ TEST_F(LLVMCodeBuilderTest, Yield)
     ASSERT_TRUE(code->isFinished(ctx.get()));
 
     // Reset unfinished coroutine
-    EXPECT_CALL(m_target, isStage()).Times(3);
+    EXPECT_CALL(m_utils.target(), isStage()).Times(3);
     testing::internal::CaptureStdout();
     code->reset(ctx.get());
     code->run(ctx.get());
@@ -1526,7 +1475,7 @@ TEST_F(LLVMCodeBuilderTest, Yield)
 
     code->reset(ctx.get());
 
-    EXPECT_CALL(m_target, isStage()).Times(3);
+    EXPECT_CALL(m_utils.target(), isStage()).Times(3);
     testing::internal::CaptureStdout();
     code->reset(ctx.get());
     code->run(ctx.get());
@@ -1534,9 +1483,9 @@ TEST_F(LLVMCodeBuilderTest, Yield)
     ASSERT_FALSE(code->isFinished(ctx.get())); // leave unfinished coroutine
 
     // With warp
-    createBuilder(true);
+    builder = m_utils.createBuilder(true);
     build();
-    code = m_builder->build();
+    code = builder->build();
     ctx = code->createExecutionContext(&thread);
 
     static const std::string expected =
@@ -1548,7 +1497,7 @@ TEST_F(LLVMCodeBuilderTest, Yield)
         "3_args test 4 5\n"
         "1_arg 3_args_output\n";
 
-    EXPECT_CALL(m_target, isStage()).Times(7);
+    EXPECT_CALL(m_utils.target(), isStage()).Times(7);
     testing::internal::CaptureStdout();
     code->run(ctx.get());
     ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
@@ -1558,8 +1507,8 @@ TEST_F(LLVMCodeBuilderTest, VariablesAfterSuspend)
 {
     Stage stage;
     Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
+    sprite.setEngine(&m_utils.engine());
+    EXPECT_CALL(m_utils.engine(), stage()).WillRepeatedly(Return(&stage));
 
     auto globalVar = std::make_shared<Variable>("", "", 87);
     stage.addVariable(globalVar);
@@ -1567,60 +1516,60 @@ TEST_F(LLVMCodeBuilderTest, VariablesAfterSuspend)
     auto localVar = std::make_shared<Variable>("", "", "test");
     sprite.addVariable(localVar);
 
-    createBuilder(&sprite, false);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(&sprite, false);
 
-    CompilerValue *v = m_builder->addConstValue(12.5);
-    m_builder->createVariableWrite(globalVar.get(), v);
+    CompilerValue *v = builder->addConstValue(12.5);
+    builder->createVariableWrite(globalVar.get(), v);
 
-    v = m_builder->addConstValue(true);
-    m_builder->createVariableWrite(localVar.get(), v);
+    v = builder->addConstValue(true);
+    builder->createVariableWrite(localVar.get(), v);
 
-    m_builder->yield();
+    builder->yield();
 
-    v = m_builder->addVariableValue(globalVar.get());
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addVariableValue(globalVar.get());
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addVariableValue(localVar.get());
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addVariableValue(localVar.get());
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addConstValue(2);
-    m_builder->beginRepeatLoop(v);
+    v = builder->addConstValue(2);
+    builder->beginRepeatLoop(v);
     {
-        v = m_builder->addConstValue(12.5);
-        m_builder->createVariableWrite(globalVar.get(), v);
+        v = builder->addConstValue(12.5);
+        builder->createVariableWrite(globalVar.get(), v);
     }
-    m_builder->endLoop();
+    builder->endLoop();
 
-    v = m_builder->addVariableValue(globalVar.get());
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addVariableValue(globalVar.get());
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addConstValue(0);
-    m_builder->createVariableWrite(localVar.get(), v);
+    v = builder->addConstValue(0);
+    builder->createVariableWrite(localVar.get(), v);
 
-    m_builder->beginLoopCondition();
-    v = m_builder->createCmpLT(m_builder->addVariableValue(localVar.get()), m_builder->addConstValue(3));
-    m_builder->beginWhileLoop(v);
-    m_builder->endLoop();
+    builder->beginLoopCondition();
+    v = builder->createCmpLT(builder->addVariableValue(localVar.get()), builder->addConstValue(3));
+    builder->beginWhileLoop(v);
+    builder->endLoop();
 
-    v = m_builder->addVariableValue(localVar.get());
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addVariableValue(localVar.get());
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addConstValue(0);
-    m_builder->createVariableWrite(localVar.get(), v);
+    v = builder->addConstValue(0);
+    builder->createVariableWrite(localVar.get(), v);
 
-    m_builder->beginLoopCondition();
-    v = m_builder->createCmpEQ(m_builder->addVariableValue(localVar.get()), m_builder->addConstValue(2));
-    m_builder->beginRepeatUntilLoop(v);
-    m_builder->endLoop();
+    builder->beginLoopCondition();
+    v = builder->createCmpEQ(builder->addVariableValue(localVar.get()), builder->addConstValue(2));
+    builder->beginRepeatUntilLoop(v);
+    builder->endLoop();
 
-    v = m_builder->addVariableValue(localVar.get());
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addVariableValue(localVar.get());
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
     std::string expected =
         "hello world\n"
         "-4.8\n";
 
-    auto code = m_builder->build();
+    auto code = builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -1691,8 +1640,8 @@ TEST_F(LLVMCodeBuilderTest, ListsAfterSuspend)
 
     Stage stage;
     Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
+    sprite.setEngine(&m_utils.engine());
+    EXPECT_CALL(m_utils.engine(), stage()).WillRepeatedly(Return(&stage));
 
     auto globalList1 = std::make_shared<List>("", "");
     stage.addList(globalList1);
@@ -1706,51 +1655,51 @@ TEST_F(LLVMCodeBuilderTest, ListsAfterSuspend)
     auto localList2 = std::make_shared<List>("", "");
     sprite.addList(localList2);
 
-    createBuilder(&sprite, false);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(&sprite, false);
 
-    m_builder->createListClear(globalList1.get());
-    m_builder->createListClear(globalList2.get());
-    m_builder->createListClear(localList1.get());
-    m_builder->createListClear(localList2.get());
+    builder->createListClear(globalList1.get());
+    builder->createListClear(globalList2.get());
+    builder->createListClear(localList1.get());
+    builder->createListClear(localList2.get());
 
-    m_builder->createListAppend(globalList1.get(), m_builder->addConstValue(1));
-    m_builder->createListAppend(globalList1.get(), m_builder->addConstValue(2));
-    m_builder->createListAppend(globalList1.get(), m_builder->addConstValue(3));
+    builder->createListAppend(globalList1.get(), builder->addConstValue(1));
+    builder->createListAppend(globalList1.get(), builder->addConstValue(2));
+    builder->createListAppend(globalList1.get(), builder->addConstValue(3));
 
-    m_builder->createListAppend(globalList2.get(), m_builder->addConstValue(1));
-    m_builder->createListAppend(globalList2.get(), m_builder->addConstValue(2));
-    m_builder->createListAppend(globalList2.get(), m_builder->addConstValue(3));
+    builder->createListAppend(globalList2.get(), builder->addConstValue(1));
+    builder->createListAppend(globalList2.get(), builder->addConstValue(2));
+    builder->createListAppend(globalList2.get(), builder->addConstValue(3));
 
-    m_builder->createListReplace(globalList2.get(), m_builder->addConstValue(1), m_builder->addConstValue(12.5));
+    builder->createListReplace(globalList2.get(), builder->addConstValue(1), builder->addConstValue(12.5));
 
-    m_builder->createListInsert(localList1.get(), m_builder->addConstValue(0), m_builder->addConstValue("Lorem"));
-    m_builder->createListInsert(localList1.get(), m_builder->addConstValue(0), m_builder->addConstValue("ipsum"));
+    builder->createListInsert(localList1.get(), builder->addConstValue(0), builder->addConstValue("Lorem"));
+    builder->createListInsert(localList1.get(), builder->addConstValue(0), builder->addConstValue("ipsum"));
 
-    m_builder->createListInsert(localList2.get(), m_builder->addConstValue(0), m_builder->addConstValue(true));
-    m_builder->createListInsert(localList2.get(), m_builder->addConstValue(0), m_builder->addConstValue(false));
+    builder->createListInsert(localList2.get(), builder->addConstValue(0), builder->addConstValue(true));
+    builder->createListInsert(localList2.get(), builder->addConstValue(0), builder->addConstValue(false));
 
-    m_builder->yield();
+    builder->yield();
 
-    CompilerValue *v = m_builder->addListItem(globalList1.get(), m_builder->addConstValue(1));
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    CompilerValue *v = builder->addListItem(globalList1.get(), builder->addConstValue(1));
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addListItem(globalList1.get(), m_builder->addConstValue(2));
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addListItem(globalList1.get(), builder->addConstValue(2));
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addListItem(globalList2.get(), m_builder->addConstValue(1));
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addListItem(globalList2.get(), builder->addConstValue(1));
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addListItem(globalList2.get(), m_builder->addConstValue(0));
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addListItem(globalList2.get(), builder->addConstValue(0));
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addListItem(localList1.get(), m_builder->addConstValue(0));
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addListItem(localList1.get(), builder->addConstValue(0));
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addListItem(localList1.get(), m_builder->addConstValue(1));
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addListItem(localList1.get(), builder->addConstValue(1));
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addListItem(localList2.get(), m_builder->addConstValue(0));
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addListItem(localList2.get(), builder->addConstValue(0));
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
     std::string expected =
         "2\n"
@@ -1761,7 +1710,7 @@ TEST_F(LLVMCodeBuilderTest, ListsAfterSuspend)
         "-5.48\n"
         "hello\n";
 
-    auto code = m_builder->build();
+    auto code = builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -1782,170 +1731,170 @@ TEST_F(LLVMCodeBuilderTest, ListsAfterSuspend)
 
 TEST_F(LLVMCodeBuilderTest, IfStatement)
 {
-    createBuilder(true);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(true);
 
     // Without else branch (const condition)
-    CompilerValue *v = m_builder->addConstValue("true");
-    m_builder->beginIfStatement(v);
-    m_builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
-    m_builder->endIf();
+    CompilerValue *v = builder->addConstValue("true");
+    builder->beginIfStatement(v);
+    builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
+    builder->endIf();
 
-    v = m_builder->addConstValue("false");
-    m_builder->beginIfStatement(v);
-    m_builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
-    m_builder->endIf();
+    v = builder->addConstValue("false");
+    builder->beginIfStatement(v);
+    builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
+    builder->endIf();
 
     // Without else branch (condition returned by function)
-    CompilerValue *v1 = m_builder->addTargetFunctionCall("test_function_no_args_ret", Compiler::StaticType::String, {}, {});
-    CompilerValue *v2 = m_builder->addConstValue("no_args_output");
-    v = m_builder->addFunctionCall("test_equals", Compiler::StaticType::Bool, { Compiler::StaticType::String, Compiler::StaticType::String }, { v1, v2 });
-    m_builder->beginIfStatement(v);
-    v = m_builder->addConstValue(0);
-    m_builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
-    m_builder->endIf();
-
-    v1 = m_builder->addTargetFunctionCall("test_function_no_args_ret", Compiler::StaticType::String, {}, {});
-    v2 = m_builder->addConstValue("");
-    v = m_builder->addFunctionCall("test_equals", Compiler::StaticType::Bool, { Compiler::StaticType::String, Compiler::StaticType::String }, { v1, v2 });
-    m_builder->beginIfStatement(v);
-    v = m_builder->addConstValue(1);
-    m_builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
-    m_builder->endIf();
+    CompilerValue *v1 = builder->addTargetFunctionCall("test_function_no_args_ret", Compiler::StaticType::String, {}, {});
+    CompilerValue *v2 = builder->addConstValue("no_args_output");
+    v = builder->addFunctionCall("test_equals", Compiler::StaticType::Bool, { Compiler::StaticType::String, Compiler::StaticType::String }, { v1, v2 });
+    builder->beginIfStatement(v);
+    v = builder->addConstValue(0);
+    builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    builder->endIf();
+
+    v1 = builder->addTargetFunctionCall("test_function_no_args_ret", Compiler::StaticType::String, {}, {});
+    v2 = builder->addConstValue("");
+    v = builder->addFunctionCall("test_equals", Compiler::StaticType::Bool, { Compiler::StaticType::String, Compiler::StaticType::String }, { v1, v2 });
+    builder->beginIfStatement(v);
+    v = builder->addConstValue(1);
+    builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    builder->endIf();
 
     // With else branch (const condition)
-    v = m_builder->addConstValue("true");
-    m_builder->beginIfStatement(v);
-    v = m_builder->addConstValue(2);
-    m_builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
-    m_builder->beginElseBranch();
-    v = m_builder->addConstValue(3);
-    m_builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
-    m_builder->endIf();
-
-    v = m_builder->addConstValue("false");
-    m_builder->beginIfStatement(v);
-    v = m_builder->addConstValue(4);
-    m_builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
-    m_builder->beginElseBranch();
-    v = m_builder->addConstValue(5);
-    m_builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
-    m_builder->endIf();
+    v = builder->addConstValue("true");
+    builder->beginIfStatement(v);
+    v = builder->addConstValue(2);
+    builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    builder->beginElseBranch();
+    v = builder->addConstValue(3);
+    builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    builder->endIf();
+
+    v = builder->addConstValue("false");
+    builder->beginIfStatement(v);
+    v = builder->addConstValue(4);
+    builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    builder->beginElseBranch();
+    v = builder->addConstValue(5);
+    builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    builder->endIf();
 
     // With else branch (condition returned by function)
-    v1 = m_builder->addTargetFunctionCall("test_function_no_args_ret", Compiler::StaticType::String, {}, {});
-    v2 = m_builder->addConstValue("no_args_output");
-    v = m_builder->addFunctionCall("test_equals", Compiler::StaticType::Bool, { Compiler::StaticType::String, Compiler::StaticType::String }, { v1, v2 });
-    m_builder->beginIfStatement(v);
-    v = m_builder->addConstValue(6);
-    m_builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
-    m_builder->beginElseBranch();
-    v = m_builder->addConstValue(7);
-    m_builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
-    m_builder->endIf();
-
-    v1 = m_builder->addTargetFunctionCall("test_function_no_args_ret", Compiler::StaticType::String, {}, {});
-    v2 = m_builder->addConstValue("");
-    v = m_builder->addFunctionCall("test_equals", Compiler::StaticType::Bool, { Compiler::StaticType::String, Compiler::StaticType::String }, { v1, v2 });
-    m_builder->beginIfStatement(v);
-    v = m_builder->addConstValue(8);
-    m_builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
-    m_builder->beginElseBranch();
-    v = m_builder->addConstValue(9);
-    m_builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
-    m_builder->endIf();
+    v1 = builder->addTargetFunctionCall("test_function_no_args_ret", Compiler::StaticType::String, {}, {});
+    v2 = builder->addConstValue("no_args_output");
+    v = builder->addFunctionCall("test_equals", Compiler::StaticType::Bool, { Compiler::StaticType::String, Compiler::StaticType::String }, { v1, v2 });
+    builder->beginIfStatement(v);
+    v = builder->addConstValue(6);
+    builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    builder->beginElseBranch();
+    v = builder->addConstValue(7);
+    builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    builder->endIf();
+
+    v1 = builder->addTargetFunctionCall("test_function_no_args_ret", Compiler::StaticType::String, {}, {});
+    v2 = builder->addConstValue("");
+    v = builder->addFunctionCall("test_equals", Compiler::StaticType::Bool, { Compiler::StaticType::String, Compiler::StaticType::String }, { v1, v2 });
+    builder->beginIfStatement(v);
+    v = builder->addConstValue(8);
+    builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    builder->beginElseBranch();
+    v = builder->addConstValue(9);
+    builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    builder->endIf();
 
     // Nested 1
-    CompilerValue *str = m_builder->addFunctionCall("test_const_string", Compiler::StaticType::String, { Compiler::StaticType::String }, { m_builder->addConstValue("test") });
-    v = m_builder->addConstValue(true);
-    m_builder->beginIfStatement(v);
+    CompilerValue *str = builder->addFunctionCall("test_const_string", Compiler::StaticType::String, { Compiler::StaticType::String }, { builder->addConstValue("test") });
+    v = builder->addConstValue(true);
+    builder->beginIfStatement(v);
     {
-        v = m_builder->addConstValue(false);
-        m_builder->beginIfStatement(v);
+        v = builder->addConstValue(false);
+        builder->beginIfStatement(v);
         {
-            v = m_builder->addConstValue(0);
-            m_builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+            v = builder->addConstValue(0);
+            builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
         }
-        m_builder->beginElseBranch();
+        builder->beginElseBranch();
         {
-            v = m_builder->addConstValue(1);
-            m_builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+            v = builder->addConstValue(1);
+            builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
             // str should still be allocated
-            m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { str });
+            builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { str });
 
-            v = m_builder->addConstValue(false);
-            m_builder->beginIfStatement(v);
-            m_builder->beginElseBranch();
+            v = builder->addConstValue(false);
+            builder->beginIfStatement(v);
+            builder->beginElseBranch();
             {
-                v = m_builder->addConstValue(2);
-                m_builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+                v = builder->addConstValue(2);
+                builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
             }
-            m_builder->endIf();
+            builder->endIf();
 
             // str should still be allocated
-            m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { str });
+            builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { str });
         }
-        m_builder->endIf();
+        builder->endIf();
     }
-    m_builder->beginElseBranch();
+    builder->beginElseBranch();
     {
-        v = m_builder->addConstValue(true);
-        m_builder->beginIfStatement(v);
+        v = builder->addConstValue(true);
+        builder->beginIfStatement(v);
         {
-            v = m_builder->addConstValue(3);
-            m_builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+            v = builder->addConstValue(3);
+            builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
         }
-        m_builder->beginElseBranch();
+        builder->beginElseBranch();
         {
-            v = m_builder->addConstValue(4);
-            m_builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+            v = builder->addConstValue(4);
+            builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
         }
-        m_builder->endIf();
+        builder->endIf();
     }
-    m_builder->endIf();
+    builder->endIf();
 
     // str should still be allocated
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { str });
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { str });
 
     // Nested 2
-    v = m_builder->addConstValue(false);
-    m_builder->beginIfStatement(v);
+    v = builder->addConstValue(false);
+    builder->beginIfStatement(v);
     {
-        v = m_builder->addConstValue(false);
-        m_builder->beginIfStatement(v);
+        v = builder->addConstValue(false);
+        builder->beginIfStatement(v);
         {
-            v = m_builder->addConstValue(5);
-            m_builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+            v = builder->addConstValue(5);
+            builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
         }
-        m_builder->beginElseBranch();
+        builder->beginElseBranch();
         {
-            v = m_builder->addConstValue(6);
-            m_builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+            v = builder->addConstValue(6);
+            builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
         }
-        m_builder->endIf();
+        builder->endIf();
     }
-    m_builder->beginElseBranch();
+    builder->beginElseBranch();
     {
-        str = m_builder->addFunctionCall("test_const_string", Compiler::StaticType::String, { Compiler::StaticType::String }, { m_builder->addConstValue("test") });
+        str = builder->addFunctionCall("test_const_string", Compiler::StaticType::String, { Compiler::StaticType::String }, { builder->addConstValue("test") });
 
-        v = m_builder->addConstValue(true);
-        m_builder->beginIfStatement(v);
+        v = builder->addConstValue(true);
+        builder->beginIfStatement(v);
         {
-            v = m_builder->addConstValue(7);
-            m_builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+            v = builder->addConstValue(7);
+            builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
         }
-        m_builder->beginElseBranch();
-        m_builder->endIf();
+        builder->beginElseBranch();
+        builder->endIf();
 
         // str should still be allocated
-        m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { str });
+        builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { str });
     }
-    m_builder->endIf();
+    builder->endIf();
 
-    auto code = m_builder->build();
-    Script script(&m_target, nullptr, nullptr);
+    auto code = builder->build();
+    Script script(&m_utils.target(), nullptr, nullptr);
     script.setCode(code);
-    Thread thread(&m_target, nullptr, &script);
+    Thread thread(&m_utils.target(), nullptr, &script);
     auto ctx = code->createExecutionContext(&thread);
 
     static const std::string expected =
@@ -1967,7 +1916,7 @@ TEST_F(LLVMCodeBuilderTest, IfStatement)
         "1_arg 7\n"
         "test\n";
 
-    EXPECT_CALL(m_target, isStage).WillRepeatedly(Return(false));
+    EXPECT_CALL(m_utils.target(), isStage).WillRepeatedly(Return(false));
     testing::internal::CaptureStdout();
     code->run(ctx.get());
     ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
@@ -1977,8 +1926,8 @@ TEST_F(LLVMCodeBuilderTest, IfStatementVariables)
 {
     Stage stage;
     Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
+    sprite.setEngine(&m_utils.engine());
+    EXPECT_CALL(m_utils.engine(), stage()).WillRepeatedly(Return(&stage));
 
     auto globalVar = std::make_shared<Variable>("", "", "test");
     stage.addVariable(globalVar);
@@ -1986,71 +1935,71 @@ TEST_F(LLVMCodeBuilderTest, IfStatementVariables)
     auto localVar = std::make_shared<Variable>("", "", 87);
     sprite.addVariable(localVar);
 
-    createBuilder(&sprite, true);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(&sprite, true);
 
-    CompilerValue *v = m_builder->addConstValue(12.5);
-    m_builder->createVariableWrite(globalVar.get(), v);
+    CompilerValue *v = builder->addConstValue(12.5);
+    builder->createVariableWrite(globalVar.get(), v);
 
-    v = m_builder->addConstValue(true);
-    m_builder->createVariableWrite(localVar.get(), v);
+    v = builder->addConstValue(true);
+    builder->createVariableWrite(localVar.get(), v);
 
-    v = m_builder->addConstValue(true);
-    m_builder->beginIfStatement(v);
+    v = builder->addConstValue(true);
+    builder->beginIfStatement(v);
     {
-        v = m_builder->addConstValue("hello world");
-        m_builder->createVariableWrite(globalVar.get(), v);
+        v = builder->addConstValue("hello world");
+        builder->createVariableWrite(globalVar.get(), v);
     }
-    m_builder->endIf();
+    builder->endIf();
 
-    v = m_builder->addVariableValue(globalVar.get());
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addVariableValue(globalVar.get());
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addConstValue(12.5);
-    m_builder->createVariableWrite(globalVar.get(), v);
+    v = builder->addConstValue(12.5);
+    builder->createVariableWrite(globalVar.get(), v);
 
-    v = m_builder->addConstValue(false);
-    m_builder->beginIfStatement(v);
+    v = builder->addConstValue(false);
+    builder->beginIfStatement(v);
     {
-        v = m_builder->addConstValue("hello world");
-        m_builder->createVariableWrite(globalVar.get(), v);
+        v = builder->addConstValue("hello world");
+        builder->createVariableWrite(globalVar.get(), v);
 
-        v = m_builder->addConstValue(0);
-        m_builder->createVariableWrite(localVar.get(), v);
+        v = builder->addConstValue(0);
+        builder->createVariableWrite(localVar.get(), v);
     }
-    m_builder->endIf();
+    builder->endIf();
 
-    v = m_builder->addVariableValue(globalVar.get());
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addVariableValue(globalVar.get());
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addVariableValue(localVar.get());
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addVariableValue(localVar.get());
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addConstValue(true);
-    m_builder->beginIfStatement(v);
+    v = builder->addConstValue(true);
+    builder->beginIfStatement(v);
     {
-        v = m_builder->addConstValue(true);
-        m_builder->beginIfStatement(v);
+        v = builder->addConstValue(true);
+        builder->beginIfStatement(v);
         {
-            v = m_builder->addConstValue(true);
-            m_builder->createVariableWrite(globalVar.get(), v);
+            v = builder->addConstValue(true);
+            builder->createVariableWrite(globalVar.get(), v);
         }
-        m_builder->endIf();
+        builder->endIf();
 
-        v = m_builder->addConstValue(false);
-        m_builder->beginIfStatement(v);
+        v = builder->addConstValue(false);
+        builder->beginIfStatement(v);
         {
-            v = m_builder->addConstValue(-8.2);
-            m_builder->createVariableWrite(localVar.get(), v);
+            v = builder->addConstValue(-8.2);
+            builder->createVariableWrite(localVar.get(), v);
         }
-        m_builder->endIf();
+        builder->endIf();
     }
-    m_builder->endIf();
+    builder->endIf();
 
-    v = m_builder->addVariableValue(globalVar.get());
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addVariableValue(globalVar.get());
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addVariableValue(localVar.get());
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addVariableValue(localVar.get());
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
     std::string expected =
         "hello world\n"
@@ -2059,7 +2008,7 @@ TEST_F(LLVMCodeBuilderTest, IfStatementVariables)
         "true\n"
         "true\n";
 
-    auto code = m_builder->build();
+    auto code = builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -2074,8 +2023,8 @@ TEST_F(LLVMCodeBuilderTest, IfStatementLists)
 {
     Stage stage;
     Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
+    sprite.setEngine(&m_utils.engine());
+    EXPECT_CALL(m_utils.engine(), stage()).WillRepeatedly(Return(&stage));
 
     auto globalList1 = std::make_shared<List>("", "");
     stage.addList(globalList1);
@@ -2086,105 +2035,105 @@ TEST_F(LLVMCodeBuilderTest, IfStatementLists)
     auto localList = std::make_shared<List>("", "");
     sprite.addList(localList);
 
-    createBuilder(&sprite, false);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(&sprite, false);
 
-    auto resetLists = [this, globalList1, globalList2, localList]() {
-        m_builder->createListClear(globalList1.get());
-        m_builder->createListClear(globalList2.get());
-        m_builder->createListClear(localList.get());
+    auto resetLists = [this, builder, globalList1, globalList2, localList]() {
+        builder->createListClear(globalList1.get());
+        builder->createListClear(globalList2.get());
+        builder->createListClear(localList.get());
 
-        m_builder->createListAppend(globalList1.get(), m_builder->addConstValue(1));
-        m_builder->createListAppend(globalList1.get(), m_builder->addConstValue(2));
+        builder->createListAppend(globalList1.get(), builder->addConstValue(1));
+        builder->createListAppend(globalList1.get(), builder->addConstValue(2));
 
-        m_builder->createListAppend(globalList2.get(), m_builder->addConstValue("hello"));
-        m_builder->createListAppend(globalList2.get(), m_builder->addConstValue("world"));
+        builder->createListAppend(globalList2.get(), builder->addConstValue("hello"));
+        builder->createListAppend(globalList2.get(), builder->addConstValue("world"));
 
-        m_builder->createListAppend(localList.get(), m_builder->addConstValue(false));
-        m_builder->createListAppend(localList.get(), m_builder->addConstValue(true));
+        builder->createListAppend(localList.get(), builder->addConstValue(false));
+        builder->createListAppend(localList.get(), builder->addConstValue(true));
     };
 
-    auto checkLists = [this, globalList1, globalList2, localList]() {
-        CompilerValue *v = m_builder->addListItem(globalList1.get(), m_builder->addConstValue(0));
-        m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    auto checkLists = [this, builder, globalList1, globalList2, localList]() {
+        CompilerValue *v = builder->addListItem(globalList1.get(), builder->addConstValue(0));
+        builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-        v = m_builder->addListItem(globalList2.get(), m_builder->addConstValue(1));
-        m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+        v = builder->addListItem(globalList2.get(), builder->addConstValue(1));
+        builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-        v = m_builder->addListItem(localList.get(), m_builder->addConstValue(0));
-        m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+        v = builder->addListItem(localList.get(), builder->addConstValue(0));
+        builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
     };
 
     // if (true)
     resetLists();
 
     CompilerValue *v, *v1, *v2;
-    v = m_builder->addConstValue(true);
-    m_builder->beginIfStatement(v);
+    v = builder->addConstValue(true);
+    builder->beginIfStatement(v);
     {
-        v = m_builder->addConstValue("hello world");
-        m_builder->createListAppend(globalList1.get(), v);
+        v = builder->addConstValue("hello world");
+        builder->createListAppend(globalList1.get(), v);
 
-        v1 = m_builder->addConstValue(0);
-        v2 = m_builder->addConstValue(8.5);
-        m_builder->createListInsert(globalList2.get(), v1, v2);
+        v1 = builder->addConstValue(0);
+        v2 = builder->addConstValue(8.5);
+        builder->createListInsert(globalList2.get(), v1, v2);
 
-        v1 = m_builder->addConstValue(1);
-        v2 = m_builder->addConstValue(-4.25);
-        m_builder->createListReplace(localList.get(), v1, v2);
+        v1 = builder->addConstValue(1);
+        v2 = builder->addConstValue(-4.25);
+        builder->createListReplace(localList.get(), v1, v2);
     }
-    m_builder->endIf();
+    builder->endIf();
 
     checkLists();
 
     // if (false)
     resetLists();
 
-    v = m_builder->addConstValue(false);
-    m_builder->beginIfStatement(v);
+    v = builder->addConstValue(false);
+    builder->beginIfStatement(v);
     {
-        v = m_builder->addConstValue("hello world");
-        m_builder->createListAppend(globalList1.get(), v);
+        v = builder->addConstValue("hello world");
+        builder->createListAppend(globalList1.get(), v);
 
-        v1 = m_builder->addConstValue(0);
-        v2 = m_builder->addConstValue(8.5);
-        m_builder->createListInsert(globalList2.get(), v1, v2);
+        v1 = builder->addConstValue(0);
+        v2 = builder->addConstValue(8.5);
+        builder->createListInsert(globalList2.get(), v1, v2);
 
-        v1 = m_builder->addConstValue(1);
-        v2 = m_builder->addConstValue(-4.25);
-        m_builder->createListReplace(localList.get(), v1, v2);
+        v1 = builder->addConstValue(1);
+        v2 = builder->addConstValue(-4.25);
+        builder->createListReplace(localList.get(), v1, v2);
     }
-    m_builder->endIf();
+    builder->endIf();
 
     checkLists();
 
     // if (true) { if (true) { ... }; if (false) { ... } }
     resetLists();
 
-    v = m_builder->addConstValue(true);
-    m_builder->beginIfStatement(v);
+    v = builder->addConstValue(true);
+    builder->beginIfStatement(v);
     {
-        v = m_builder->addConstValue(true);
-        m_builder->beginIfStatement(v);
+        v = builder->addConstValue(true);
+        builder->beginIfStatement(v);
         {
-            v = m_builder->addConstValue("hello world");
-            m_builder->createListAppend(globalList1.get(), v);
+            v = builder->addConstValue("hello world");
+            builder->createListAppend(globalList1.get(), v);
 
-            v1 = m_builder->addConstValue(0);
-            v2 = m_builder->addConstValue(8.5);
-            m_builder->createListInsert(globalList2.get(), v1, v2);
+            v1 = builder->addConstValue(0);
+            v2 = builder->addConstValue(8.5);
+            builder->createListInsert(globalList2.get(), v1, v2);
         }
-        m_builder->endIf();
+        builder->endIf();
 
-        v = m_builder->addConstValue(false);
-        m_builder->beginIfStatement(v);
+        v = builder->addConstValue(false);
+        builder->beginIfStatement(v);
         {
-            v1 = m_builder->addConstValue(1);
-            v2 = m_builder->addConstValue(-4.25);
-            m_builder->createListReplace(localList.get(), v1, v2);
+            v1 = builder->addConstValue(1);
+            v2 = builder->addConstValue(-4.25);
+            builder->createListReplace(localList.get(), v1, v2);
         }
-        m_builder->endIf();
+        builder->endIf();
     }
-    m_builder->endIf();
+    builder->endIf();
 
     checkLists();
 
@@ -2199,7 +2148,7 @@ TEST_F(LLVMCodeBuilderTest, IfStatementLists)
         "hello\n"
         "false\n";
 
-    auto code = m_builder->build();
+    auto code = builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -2212,80 +2161,80 @@ TEST_F(LLVMCodeBuilderTest, IfStatementLists)
 
 TEST_F(LLVMCodeBuilderTest, RepeatLoop)
 {
-    createBuilder(true);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(true);
 
     // Const count
-    CompilerValue *v = m_builder->addConstValue("-5");
-    m_builder->beginRepeatLoop(v);
-    m_builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
-    m_builder->endLoop();
-
-    v = m_builder->addConstValue(0);
-    m_builder->beginRepeatLoop(v);
-    m_builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
-    m_builder->endLoop();
-
-    v = m_builder->addConstValue(3);
-    m_builder->beginRepeatLoop(v);
-    m_builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
-    m_builder->endLoop();
-
-    v = m_builder->addConstValue("2.4");
-    m_builder->beginRepeatLoop(v);
-    v = m_builder->addConstValue(0);
-    m_builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
-    m_builder->endLoop();
-
-    v = m_builder->addConstValue("2.5");
-    m_builder->beginRepeatLoop(v);
-    v = m_builder->addConstValue(1);
-    m_builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
-    m_builder->endLoop();
+    CompilerValue *v = builder->addConstValue("-5");
+    builder->beginRepeatLoop(v);
+    builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
+    builder->endLoop();
+
+    v = builder->addConstValue(0);
+    builder->beginRepeatLoop(v);
+    builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
+    builder->endLoop();
+
+    v = builder->addConstValue(3);
+    builder->beginRepeatLoop(v);
+    builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
+    builder->endLoop();
+
+    v = builder->addConstValue("2.4");
+    builder->beginRepeatLoop(v);
+    v = builder->addConstValue(0);
+    builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    builder->endLoop();
+
+    v = builder->addConstValue("2.5");
+    builder->beginRepeatLoop(v);
+    v = builder->addConstValue(1);
+    builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    builder->endLoop();
 
     // Count returned by function
-    v = m_builder->addConstValue(2);
-    v = callConstFuncForType(ValueType::Number, v);
-    m_builder->beginRepeatLoop(v);
-    CompilerValue *index = m_builder->addLoopIndex();
-    m_builder->addTargetFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { index });
-    m_builder->endLoop();
+    v = builder->addConstValue(2);
+    v = m_utils.callConstFuncForType(ValueType::Number, v);
+    builder->beginRepeatLoop(v);
+    CompilerValue *index = builder->addLoopIndex();
+    builder->addTargetFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { index });
+    builder->endLoop();
 
     // Nested
-    CompilerValue *str = m_builder->addFunctionCall("test_const_string", Compiler::StaticType::String, { Compiler::StaticType::String }, { m_builder->addConstValue("test") });
-    v = m_builder->addConstValue(2);
-    m_builder->beginRepeatLoop(v);
+    CompilerValue *str = builder->addFunctionCall("test_const_string", Compiler::StaticType::String, { Compiler::StaticType::String }, { builder->addConstValue("test") });
+    v = builder->addConstValue(2);
+    builder->beginRepeatLoop(v);
     {
-        v = m_builder->addConstValue(2);
-        m_builder->beginRepeatLoop(v);
+        v = builder->addConstValue(2);
+        builder->beginRepeatLoop(v);
         {
-            v = m_builder->addConstValue(1);
-            m_builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+            v = builder->addConstValue(1);
+            builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
             // str should still be allocated
-            m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { str });
+            builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { str });
         }
-        m_builder->endLoop();
+        builder->endLoop();
 
-        v = m_builder->addConstValue(2);
-        m_builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+        v = builder->addConstValue(2);
+        builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-        v = m_builder->addConstValue(3);
-        m_builder->beginRepeatLoop(v);
+        v = builder->addConstValue(3);
+        builder->beginRepeatLoop(v);
         {
-            index = m_builder->addLoopIndex();
-            m_builder->addTargetFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { index });
+            index = builder->addLoopIndex();
+            builder->addTargetFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { index });
         }
-        m_builder->endLoop();
+        builder->endLoop();
     }
-    m_builder->endLoop();
+    builder->endLoop();
 
     // str should still be allocated
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { str });
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { str });
 
-    auto code = m_builder->build();
-    Script script(&m_target, nullptr, nullptr);
+    auto code = builder->build();
+    Script script(&m_utils.target(), nullptr, nullptr);
     script.setCode(code);
-    Thread thread(&m_target, nullptr, &script);
+    Thread thread(&m_utils.target(), nullptr, &script);
     auto ctx = code->createExecutionContext(&thread);
 
     static const std::string expected =
@@ -2317,25 +2266,25 @@ TEST_F(LLVMCodeBuilderTest, RepeatLoop)
         "2\n"
         "test\n";
 
-    EXPECT_CALL(m_target, isStage).WillRepeatedly(Return(false));
+    EXPECT_CALL(m_utils.target(), isStage).WillRepeatedly(Return(false));
     testing::internal::CaptureStdout();
     code->run(ctx.get());
     ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
 
     // Yield
-    createBuilder(false);
+    builder = m_utils.createBuilder(false);
 
-    v = m_builder->addConstValue(3);
-    m_builder->beginRepeatLoop(v);
-    m_builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
-    m_builder->endLoop();
+    v = builder->addConstValue(3);
+    builder->beginRepeatLoop(v);
+    builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
+    builder->endLoop();
 
-    code = m_builder->build();
+    code = builder->build();
     ctx = code->createExecutionContext(&thread);
 
     static const std::string expected1 = "no_args\n";
 
-    EXPECT_CALL(m_target, isStage).WillRepeatedly(Return(false));
+    EXPECT_CALL(m_utils.target(), isStage).WillRepeatedly(Return(false));
 
     for (int i = 0; i < 3; i++) {
         testing::internal::CaptureStdout();
@@ -2350,26 +2299,26 @@ TEST_F(LLVMCodeBuilderTest, RepeatLoop)
     ASSERT_TRUE(code->isFinished(ctx.get()));
 
     // No warp no-op loop
-    createBuilder(false);
+    builder = m_utils.createBuilder(false);
 
-    v = m_builder->addConstValue(0); // don't yield
-    m_builder->beginRepeatLoop(v);
-    m_builder->endLoop();
+    v = builder->addConstValue(0); // don't yield
+    builder->beginRepeatLoop(v);
+    builder->endLoop();
 
-    code = m_builder->build();
+    code = builder->build();
     ctx = code->createExecutionContext(&thread);
     code->run(ctx.get());
     ASSERT_TRUE(code->isFinished(ctx.get()));
 
     // Infinite no warp loop
-    createBuilder(false);
+    builder = m_utils.createBuilder(false);
 
-    v = m_builder->addConstValue("Infinity");
-    m_builder->beginRepeatLoop(v);
-    m_builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
-    m_builder->endLoop();
+    v = builder->addConstValue("Infinity");
+    builder->beginRepeatLoop(v);
+    builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
+    builder->endLoop();
 
-    code = m_builder->build();
+    code = builder->build();
     ctx = code->createExecutionContext(&thread);
 
     for (int i = 0; i < 10; i++) {
@@ -2382,70 +2331,70 @@ TEST_F(LLVMCodeBuilderTest, RepeatLoop)
 
 TEST_F(LLVMCodeBuilderTest, WhileLoop)
 {
-    createBuilder(true);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(true);
 
     // Const condition
-    m_builder->beginLoopCondition();
-    CompilerValue *v = m_builder->addConstValue("false");
-    m_builder->beginWhileLoop(v);
-    m_builder->addFunctionCall("test_unreachable", Compiler::StaticType::Void, {}, {});
-    m_builder->endLoop();
-
-    m_builder->beginLoopCondition();
-    v = m_builder->addConstValue(false);
-    m_builder->beginWhileLoop(v);
-    m_builder->addFunctionCall("test_unreachable", Compiler::StaticType::Void, {}, {});
-    m_builder->endLoop();
+    builder->beginLoopCondition();
+    CompilerValue *v = builder->addConstValue("false");
+    builder->beginWhileLoop(v);
+    builder->addFunctionCall("test_unreachable", Compiler::StaticType::Void, {}, {});
+    builder->endLoop();
+
+    builder->beginLoopCondition();
+    v = builder->addConstValue(false);
+    builder->beginWhileLoop(v);
+    builder->addFunctionCall("test_unreachable", Compiler::StaticType::Void, {}, {});
+    builder->endLoop();
 
     // Condition returned by function
-    m_builder->addFunctionCall("test_reset_counter", Compiler::StaticType::Void, {}, {});
-    m_builder->beginLoopCondition();
-    CompilerValue *v1 = m_builder->addFunctionCall("test_get_counter", Compiler::StaticType::Number, {}, {});
-    CompilerValue *v2 = m_builder->addConstValue(2);
-    v = m_builder->addFunctionCall("test_lower_than", Compiler::StaticType::Bool, { Compiler::StaticType::Number, Compiler::StaticType::Number }, { v1, v2 });
-    m_builder->beginWhileLoop(v);
-    v = m_builder->addConstValue(0);
-    m_builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
-    m_builder->addFunctionCall("test_increment_counter", Compiler::StaticType::Void, {}, {});
-    m_builder->endLoop();
+    builder->addFunctionCall("test_reset_counter", Compiler::StaticType::Void, {}, {});
+    builder->beginLoopCondition();
+    CompilerValue *v1 = builder->addFunctionCall("test_get_counter", Compiler::StaticType::Number, {}, {});
+    CompilerValue *v2 = builder->addConstValue(2);
+    v = builder->addFunctionCall("test_lower_than", Compiler::StaticType::Bool, { Compiler::StaticType::Number, Compiler::StaticType::Number }, { v1, v2 });
+    builder->beginWhileLoop(v);
+    v = builder->addConstValue(0);
+    builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    builder->addFunctionCall("test_increment_counter", Compiler::StaticType::Void, {}, {});
+    builder->endLoop();
 
     // Nested
-    m_builder->addFunctionCall("test_reset_counter", Compiler::StaticType::Void, {}, {});
-    m_builder->beginLoopCondition();
-    v1 = m_builder->addFunctionCall("test_get_counter", Compiler::StaticType::Number, {}, {});
-    v2 = m_builder->addConstValue(3);
-    v = m_builder->addFunctionCall("test_lower_than", Compiler::StaticType::Bool, { Compiler::StaticType::Number, Compiler::StaticType::Number }, { v1, v2 });
-    m_builder->beginWhileLoop(v);
+    builder->addFunctionCall("test_reset_counter", Compiler::StaticType::Void, {}, {});
+    builder->beginLoopCondition();
+    v1 = builder->addFunctionCall("test_get_counter", Compiler::StaticType::Number, {}, {});
+    v2 = builder->addConstValue(3);
+    v = builder->addFunctionCall("test_lower_than", Compiler::StaticType::Bool, { Compiler::StaticType::Number, Compiler::StaticType::Number }, { v1, v2 });
+    builder->beginWhileLoop(v);
     {
-        m_builder->beginLoopCondition();
-        v1 = m_builder->addFunctionCall("test_get_counter", Compiler::StaticType::Number, {}, {});
-        v2 = m_builder->addConstValue(3);
-        v = m_builder->addFunctionCall("test_lower_than", Compiler::StaticType::Bool, { Compiler::StaticType::Number, Compiler::StaticType::Number }, { v1, v2 });
-        m_builder->beginWhileLoop(v);
+        builder->beginLoopCondition();
+        v1 = builder->addFunctionCall("test_get_counter", Compiler::StaticType::Number, {}, {});
+        v2 = builder->addConstValue(3);
+        v = builder->addFunctionCall("test_lower_than", Compiler::StaticType::Bool, { Compiler::StaticType::Number, Compiler::StaticType::Number }, { v1, v2 });
+        builder->beginWhileLoop(v);
         {
-            v = m_builder->addConstValue(1);
-            m_builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
-            m_builder->addFunctionCall("test_increment_counter", Compiler::StaticType::Void, {}, {});
+            v = builder->addConstValue(1);
+            builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+            builder->addFunctionCall("test_increment_counter", Compiler::StaticType::Void, {}, {});
         }
-        m_builder->endLoop();
+        builder->endLoop();
 
-        v = m_builder->addConstValue(2);
-        m_builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+        v = builder->addConstValue(2);
+        builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-        m_builder->beginLoopCondition();
-        v = m_builder->addConstValue(false);
-        m_builder->beginWhileLoop(v);
+        builder->beginLoopCondition();
+        v = builder->addConstValue(false);
+        builder->beginWhileLoop(v);
         {
-            m_builder->addFunctionCall("test_unreachable", Compiler::StaticType::Void, {}, {});
+            builder->addFunctionCall("test_unreachable", Compiler::StaticType::Void, {}, {});
         }
-        m_builder->endLoop();
+        builder->endLoop();
     }
-    m_builder->endLoop();
+    builder->endLoop();
 
-    auto code = m_builder->build();
-    Script script(&m_target, nullptr, nullptr);
+    auto code = builder->build();
+    Script script(&m_utils.target(), nullptr, nullptr);
     script.setCode(code);
-    Thread thread(&m_target, nullptr, &script);
+    Thread thread(&m_utils.target(), nullptr, &script);
     auto ctx = code->createExecutionContext(&thread);
 
     static const std::string expected =
@@ -2456,26 +2405,26 @@ TEST_F(LLVMCodeBuilderTest, WhileLoop)
         "1_arg 1\n"
         "1_arg 2\n";
 
-    EXPECT_CALL(m_target, isStage).WillRepeatedly(Return(false));
+    EXPECT_CALL(m_utils.target(), isStage).WillRepeatedly(Return(false));
     testing::internal::CaptureStdout();
     code->run(ctx.get());
     ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
 
     // Yield
-    createBuilder(false);
+    builder = m_utils.createBuilder(false);
 
-    m_builder->beginLoopCondition();
-    v = m_builder->addConstValue(true);
-    m_builder->beginWhileLoop(v);
-    m_builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
-    m_builder->endLoop();
+    builder->beginLoopCondition();
+    v = builder->addConstValue(true);
+    builder->beginWhileLoop(v);
+    builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
+    builder->endLoop();
 
-    code = m_builder->build();
+    code = builder->build();
     ctx = code->createExecutionContext(&thread);
 
     static const std::string expected1 = "no_args\n";
 
-    EXPECT_CALL(m_target, isStage).WillRepeatedly(Return(false));
+    EXPECT_CALL(m_utils.target(), isStage).WillRepeatedly(Return(false));
 
     for (int i = 0; i < 10; i++) {
         testing::internal::CaptureStdout();
@@ -2487,73 +2436,73 @@ TEST_F(LLVMCodeBuilderTest, WhileLoop)
 
 TEST_F(LLVMCodeBuilderTest, RepeatUntilLoop)
 {
-    createBuilder(true);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(true);
 
     // Const condition
-    m_builder->beginLoopCondition();
-    CompilerValue *v = m_builder->addConstValue("true");
-    m_builder->beginRepeatUntilLoop(v);
-    m_builder->addFunctionCall("test_unreachable", Compiler::StaticType::Void, {}, {});
-    m_builder->endLoop();
-
-    m_builder->beginLoopCondition();
-    v = m_builder->addConstValue(true);
-    m_builder->beginRepeatUntilLoop(v);
-    m_builder->addFunctionCall("test_unreachable", Compiler::StaticType::Void, {}, {});
-    m_builder->endLoop();
+    builder->beginLoopCondition();
+    CompilerValue *v = builder->addConstValue("true");
+    builder->beginRepeatUntilLoop(v);
+    builder->addFunctionCall("test_unreachable", Compiler::StaticType::Void, {}, {});
+    builder->endLoop();
+
+    builder->beginLoopCondition();
+    v = builder->addConstValue(true);
+    builder->beginRepeatUntilLoop(v);
+    builder->addFunctionCall("test_unreachable", Compiler::StaticType::Void, {}, {});
+    builder->endLoop();
 
     // Condition returned by function
-    m_builder->addFunctionCall("test_reset_counter", Compiler::StaticType::Void, {}, {});
-    m_builder->beginLoopCondition();
-    CompilerValue *v1 = m_builder->addFunctionCall("test_get_counter", Compiler::StaticType::Number, {}, {});
-    CompilerValue *v2 = m_builder->addConstValue(2);
-    v = m_builder->addFunctionCall("test_lower_than", Compiler::StaticType::Bool, { Compiler::StaticType::Number, Compiler::StaticType::Number }, { v1, v2 });
-    v = m_builder->addFunctionCall("test_not", Compiler::StaticType::Bool, { Compiler::StaticType::Bool }, { v });
-    m_builder->beginRepeatUntilLoop(v);
-    v = m_builder->addConstValue(0);
-    m_builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
-    m_builder->addFunctionCall("test_increment_counter", Compiler::StaticType::Void, {}, {});
-    m_builder->endLoop();
+    builder->addFunctionCall("test_reset_counter", Compiler::StaticType::Void, {}, {});
+    builder->beginLoopCondition();
+    CompilerValue *v1 = builder->addFunctionCall("test_get_counter", Compiler::StaticType::Number, {}, {});
+    CompilerValue *v2 = builder->addConstValue(2);
+    v = builder->addFunctionCall("test_lower_than", Compiler::StaticType::Bool, { Compiler::StaticType::Number, Compiler::StaticType::Number }, { v1, v2 });
+    v = builder->addFunctionCall("test_not", Compiler::StaticType::Bool, { Compiler::StaticType::Bool }, { v });
+    builder->beginRepeatUntilLoop(v);
+    v = builder->addConstValue(0);
+    builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    builder->addFunctionCall("test_increment_counter", Compiler::StaticType::Void, {}, {});
+    builder->endLoop();
 
     // Nested
-    m_builder->addFunctionCall("test_reset_counter", Compiler::StaticType::Void, {}, {});
-    m_builder->beginLoopCondition();
-    v1 = m_builder->addFunctionCall("test_get_counter", Compiler::StaticType::Number, {}, {});
-    v2 = m_builder->addConstValue(3);
-    v = m_builder->addFunctionCall("test_lower_than", Compiler::StaticType::Bool, { Compiler::StaticType::Number, Compiler::StaticType::Number }, { v1, v2 });
-    v = m_builder->addFunctionCall("test_not", Compiler::StaticType::Bool, { Compiler::StaticType::Bool }, { v });
-    m_builder->beginRepeatUntilLoop(v);
+    builder->addFunctionCall("test_reset_counter", Compiler::StaticType::Void, {}, {});
+    builder->beginLoopCondition();
+    v1 = builder->addFunctionCall("test_get_counter", Compiler::StaticType::Number, {}, {});
+    v2 = builder->addConstValue(3);
+    v = builder->addFunctionCall("test_lower_than", Compiler::StaticType::Bool, { Compiler::StaticType::Number, Compiler::StaticType::Number }, { v1, v2 });
+    v = builder->addFunctionCall("test_not", Compiler::StaticType::Bool, { Compiler::StaticType::Bool }, { v });
+    builder->beginRepeatUntilLoop(v);
     {
-        m_builder->beginLoopCondition();
-        v1 = m_builder->addFunctionCall("test_get_counter", Compiler::StaticType::Number, {}, {});
-        v2 = m_builder->addConstValue(3);
-        v = m_builder->addFunctionCall("test_lower_than", Compiler::StaticType::Bool, { Compiler::StaticType::Number, Compiler::StaticType::Number }, { v1, v2 });
-        v = m_builder->addFunctionCall("test_not", Compiler::StaticType::Bool, { Compiler::StaticType::Bool }, { v });
-        m_builder->beginRepeatUntilLoop(v);
+        builder->beginLoopCondition();
+        v1 = builder->addFunctionCall("test_get_counter", Compiler::StaticType::Number, {}, {});
+        v2 = builder->addConstValue(3);
+        v = builder->addFunctionCall("test_lower_than", Compiler::StaticType::Bool, { Compiler::StaticType::Number, Compiler::StaticType::Number }, { v1, v2 });
+        v = builder->addFunctionCall("test_not", Compiler::StaticType::Bool, { Compiler::StaticType::Bool }, { v });
+        builder->beginRepeatUntilLoop(v);
         {
-            v = m_builder->addConstValue(1);
-            m_builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
-            m_builder->addFunctionCall("test_increment_counter", Compiler::StaticType::Void, {}, {});
+            v = builder->addConstValue(1);
+            builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+            builder->addFunctionCall("test_increment_counter", Compiler::StaticType::Void, {}, {});
         }
-        m_builder->endLoop();
+        builder->endLoop();
 
-        v = m_builder->addConstValue(2);
-        m_builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+        v = builder->addConstValue(2);
+        builder->addTargetFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-        m_builder->beginLoopCondition();
-        v = m_builder->addConstValue(true);
-        m_builder->beginRepeatUntilLoop(v);
+        builder->beginLoopCondition();
+        v = builder->addConstValue(true);
+        builder->beginRepeatUntilLoop(v);
         {
-            m_builder->addFunctionCall("test_unreachable", Compiler::StaticType::Void, {}, {});
+            builder->addFunctionCall("test_unreachable", Compiler::StaticType::Void, {}, {});
         }
-        m_builder->endLoop();
+        builder->endLoop();
     }
-    m_builder->endLoop();
+    builder->endLoop();
 
-    auto code = m_builder->build();
-    Script script(&m_target, nullptr, nullptr);
+    auto code = builder->build();
+    Script script(&m_utils.target(), nullptr, nullptr);
     script.setCode(code);
-    Thread thread(&m_target, nullptr, &script);
+    Thread thread(&m_utils.target(), nullptr, &script);
     auto ctx = code->createExecutionContext(&thread);
 
     static const std::string expected =
@@ -2564,26 +2513,26 @@ TEST_F(LLVMCodeBuilderTest, RepeatUntilLoop)
         "1_arg 1\n"
         "1_arg 2\n";
 
-    EXPECT_CALL(m_target, isStage).WillRepeatedly(Return(false));
+    EXPECT_CALL(m_utils.target(), isStage).WillRepeatedly(Return(false));
     testing::internal::CaptureStdout();
     code->run(ctx.get());
     ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
 
     // Yield
-    createBuilder(false);
+    builder = m_utils.createBuilder(false);
 
-    m_builder->beginLoopCondition();
-    v = m_builder->addConstValue(false);
-    m_builder->beginRepeatUntilLoop(v);
-    m_builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
-    m_builder->endLoop();
+    builder->beginLoopCondition();
+    v = builder->addConstValue(false);
+    builder->beginRepeatUntilLoop(v);
+    builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
+    builder->endLoop();
 
-    code = m_builder->build();
+    code = builder->build();
     ctx = code->createExecutionContext(&thread);
 
     static const std::string expected1 = "no_args\n";
 
-    EXPECT_CALL(m_target, isStage).WillRepeatedly(Return(false));
+    EXPECT_CALL(m_utils.target(), isStage).WillRepeatedly(Return(false));
 
     for (int i = 0; i < 10; i++) {
         testing::internal::CaptureStdout();
@@ -2597,8 +2546,8 @@ TEST_F(LLVMCodeBuilderTest, LoopVariables)
 {
     Stage stage;
     Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
+    sprite.setEngine(&m_utils.engine());
+    EXPECT_CALL(m_utils.engine(), stage()).WillRepeatedly(Return(&stage));
 
     auto globalVar = std::make_shared<Variable>("", "", "test");
     stage.addVariable(globalVar);
@@ -2610,103 +2559,103 @@ TEST_F(LLVMCodeBuilderTest, LoopVariables)
     sprite.addVariable(counter1);
     sprite.addVariable(counter2);
 
-    createBuilder(&sprite, true);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(&sprite, true);
 
-    CompilerValue *v = m_builder->addConstValue(12.5);
-    m_builder->createVariableWrite(globalVar.get(), v);
+    CompilerValue *v = builder->addConstValue(12.5);
+    builder->createVariableWrite(globalVar.get(), v);
 
-    v = m_builder->addConstValue(true);
-    m_builder->createVariableWrite(localVar.get(), v);
+    v = builder->addConstValue(true);
+    builder->createVariableWrite(localVar.get(), v);
 
-    v = m_builder->addConstValue(2);
-    m_builder->beginRepeatLoop(v);
+    v = builder->addConstValue(2);
+    builder->beginRepeatLoop(v);
     {
-        v = m_builder->addConstValue("hello world");
-        m_builder->createVariableWrite(globalVar.get(), v);
+        v = builder->addConstValue("hello world");
+        builder->createVariableWrite(globalVar.get(), v);
     }
-    m_builder->endLoop();
+    builder->endLoop();
 
-    v = m_builder->addVariableValue(globalVar.get());
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addVariableValue(globalVar.get());
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addConstValue(12.5);
-    m_builder->createVariableWrite(globalVar.get(), v);
+    v = builder->addConstValue(12.5);
+    builder->createVariableWrite(globalVar.get(), v);
 
-    v = m_builder->addConstValue(0);
-    m_builder->beginRepeatLoop(v);
+    v = builder->addConstValue(0);
+    builder->beginRepeatLoop(v);
     {
-        v = m_builder->addConstValue("hello world");
-        m_builder->createVariableWrite(globalVar.get(), v);
+        v = builder->addConstValue("hello world");
+        builder->createVariableWrite(globalVar.get(), v);
 
-        v = m_builder->addConstValue(0);
-        m_builder->createVariableWrite(localVar.get(), v);
+        v = builder->addConstValue(0);
+        builder->createVariableWrite(localVar.get(), v);
     }
-    m_builder->endLoop();
+    builder->endLoop();
 
-    v = m_builder->addVariableValue(globalVar.get());
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addVariableValue(globalVar.get());
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addVariableValue(localVar.get());
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addVariableValue(localVar.get());
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addConstValue(0);
-    m_builder->createVariableWrite(counter1.get(), v);
+    v = builder->addConstValue(0);
+    builder->createVariableWrite(counter1.get(), v);
 
-    m_builder->beginLoopCondition();
-    CompilerValue *v1 = m_builder->addVariableValue(counter1.get());
-    CompilerValue *v2 = m_builder->addConstValue(5);
-    v = m_builder->createCmpLT(v1, v2);
-    m_builder->beginWhileLoop(v);
+    builder->beginLoopCondition();
+    CompilerValue *v1 = builder->addVariableValue(counter1.get());
+    CompilerValue *v2 = builder->addConstValue(5);
+    v = builder->createCmpLT(v1, v2);
+    builder->beginWhileLoop(v);
     {
-        v = m_builder->addConstValue(0);
-        m_builder->createVariableWrite(counter2.get(), v);
-
-        m_builder->beginLoopCondition();
-        v1 = m_builder->addVariableValue(counter2.get());
-        v2 = m_builder->addConstValue(3);
-        v = m_builder->createCmpEQ(v1, v2);
-        m_builder->beginRepeatUntilLoop(v);
+        v = builder->addConstValue(0);
+        builder->createVariableWrite(counter2.get(), v);
+
+        builder->beginLoopCondition();
+        v1 = builder->addVariableValue(counter2.get());
+        v2 = builder->addConstValue(3);
+        v = builder->createCmpEQ(v1, v2);
+        builder->beginRepeatUntilLoop(v);
         {
-            v = m_builder->addConstValue(true);
-            m_builder->createVariableWrite(globalVar.get(), v);
+            v = builder->addConstValue(true);
+            builder->createVariableWrite(globalVar.get(), v);
 
-            v1 = m_builder->addVariableValue(counter2.get());
-            v2 = m_builder->addConstValue(1);
-            v = m_builder->createAdd(v1, v2);
-            m_builder->createVariableWrite(counter2.get(), v);
+            v1 = builder->addVariableValue(counter2.get());
+            v2 = builder->addConstValue(1);
+            v = builder->createAdd(v1, v2);
+            builder->createVariableWrite(counter2.get(), v);
         }
-        m_builder->endLoop();
+        builder->endLoop();
 
-        m_builder->beginLoopCondition();
-        v = m_builder->addConstValue(false);
-        m_builder->beginWhileLoop(v);
+        builder->beginLoopCondition();
+        v = builder->addConstValue(false);
+        builder->beginWhileLoop(v);
         {
-            v = m_builder->addConstValue(-8.2);
-            m_builder->createVariableWrite(localVar.get(), v);
+            v = builder->addConstValue(-8.2);
+            builder->createVariableWrite(localVar.get(), v);
         }
-        m_builder->endLoop();
+        builder->endLoop();
 
-        v1 = m_builder->addVariableValue(counter1.get());
-        v2 = m_builder->addConstValue(1);
-        v = m_builder->createAdd(v1, v2);
-        m_builder->createVariableWrite(counter1.get(), v);
+        v1 = builder->addVariableValue(counter1.get());
+        v2 = builder->addConstValue(1);
+        v = builder->createAdd(v1, v2);
+        builder->createVariableWrite(counter1.get(), v);
     }
-    m_builder->endLoop();
+    builder->endLoop();
 
-    m_builder->beginLoopCondition();
-    v = m_builder->addConstValue(true);
-    m_builder->beginRepeatUntilLoop(v);
+    builder->beginLoopCondition();
+    v = builder->addConstValue(true);
+    builder->beginRepeatUntilLoop(v);
     {
-        v = m_builder->addConstValue(-8.2);
-        m_builder->createVariableWrite(localVar.get(), v);
+        v = builder->addConstValue(-8.2);
+        builder->createVariableWrite(localVar.get(), v);
     }
-    m_builder->endLoop();
+    builder->endLoop();
 
-    v = m_builder->addVariableValue(globalVar.get());
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addVariableValue(globalVar.get());
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addVariableValue(localVar.get());
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addVariableValue(localVar.get());
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
     std::string expected =
         "hello world\n"
@@ -2715,7 +2664,7 @@ TEST_F(LLVMCodeBuilderTest, LoopVariables)
         "true\n"
         "true\n";
 
-    auto code = m_builder->build();
+    auto code = builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -2731,8 +2680,8 @@ TEST_F(LLVMCodeBuilderTest, VariableLoopTypeAnalysis)
     // This just makes sure the type analyzer is used correctly
     Stage stage;
     Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
+    sprite.setEngine(&m_utils.engine());
+    EXPECT_CALL(m_utils.engine(), stage()).WillRepeatedly(Return(&stage));
 
     auto globalVar = std::make_shared<Variable>("", "");
     stage.addVariable(globalVar);
@@ -2740,28 +2689,28 @@ TEST_F(LLVMCodeBuilderTest, VariableLoopTypeAnalysis)
     auto localVar = std::make_shared<Variable>("", "");
     sprite.addVariable(localVar);
 
-    createBuilder(&sprite, true);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(&sprite, true);
 
-    CompilerValue *v = m_builder->addConstValue(5.25);
-    m_builder->createVariableWrite(localVar.get(), v);
+    CompilerValue *v = builder->addConstValue(5.25);
+    builder->createVariableWrite(localVar.get(), v);
 
-    v = m_builder->addConstValue(2);
-    m_builder->beginRepeatLoop(v);
+    v = builder->addConstValue(2);
+    builder->beginRepeatLoop(v);
     {
         // Type is unknown here because a string is assigned later
-        v = m_builder->addVariableValue(localVar.get());
-        m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
+        v = builder->addVariableValue(localVar.get());
+        builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
 
-        v = m_builder->addConstValue("test");
-        m_builder->createVariableWrite(localVar.get(), v);
+        v = builder->addConstValue("test");
+        builder->createVariableWrite(localVar.get(), v);
     }
-    m_builder->endLoop();
+    builder->endLoop();
 
     std::string expected =
         "5.25\n"
         "0\n";
 
-    auto code = m_builder->build();
+    auto code = builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     Thread thread(&sprite, nullptr, &script);
@@ -2775,8 +2724,8 @@ TEST_F(LLVMCodeBuilderTest, LoopLists)
 {
     Stage stage;
     Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
+    sprite.setEngine(&m_utils.engine());
+    EXPECT_CALL(m_utils.engine(), stage()).WillRepeatedly(Return(&stage));
 
     auto globalList1 = std::make_shared<List>("", "");
     stage.addList(globalList1);
@@ -2792,150 +2741,150 @@ TEST_F(LLVMCodeBuilderTest, LoopLists)
     sprite.addVariable(counter1);
     sprite.addVariable(counter2);
 
-    createBuilder(&sprite, true);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(&sprite, true);
 
-    auto resetLists = [this, globalList1, globalList2, localList]() {
-        m_builder->createListClear(globalList1.get());
-        m_builder->createListClear(globalList2.get());
-        m_builder->createListClear(localList.get());
+    auto resetLists = [this, builder, globalList1, globalList2, localList]() {
+        builder->createListClear(globalList1.get());
+        builder->createListClear(globalList2.get());
+        builder->createListClear(localList.get());
 
-        m_builder->createListAppend(globalList1.get(), m_builder->addConstValue(1));
-        m_builder->createListAppend(globalList1.get(), m_builder->addConstValue(2));
+        builder->createListAppend(globalList1.get(), builder->addConstValue(1));
+        builder->createListAppend(globalList1.get(), builder->addConstValue(2));
 
-        m_builder->createListAppend(globalList2.get(), m_builder->addConstValue("hello"));
-        m_builder->createListAppend(globalList2.get(), m_builder->addConstValue("world"));
+        builder->createListAppend(globalList2.get(), builder->addConstValue("hello"));
+        builder->createListAppend(globalList2.get(), builder->addConstValue("world"));
 
-        m_builder->createListAppend(localList.get(), m_builder->addConstValue(false));
-        m_builder->createListAppend(localList.get(), m_builder->addConstValue(true));
+        builder->createListAppend(localList.get(), builder->addConstValue(false));
+        builder->createListAppend(localList.get(), builder->addConstValue(true));
     };
 
-    auto checkLists = [this, globalList1, globalList2, localList]() {
-        CompilerValue *v = m_builder->addListItem(globalList1.get(), m_builder->addConstValue(0));
-        m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    auto checkLists = [this, builder, globalList1, globalList2, localList]() {
+        CompilerValue *v = builder->addListItem(globalList1.get(), builder->addConstValue(0));
+        builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-        v = m_builder->addListItem(globalList2.get(), m_builder->addConstValue(1));
-        m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+        v = builder->addListItem(globalList2.get(), builder->addConstValue(1));
+        builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-        v = m_builder->addListItem(localList.get(), m_builder->addConstValue(0));
-        m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+        v = builder->addListItem(localList.get(), builder->addConstValue(0));
+        builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
     };
 
     // repeat (2)
     resetLists();
 
     CompilerValue *v, *v1, *v2;
-    v = m_builder->addConstValue(2);
-    m_builder->beginRepeatLoop(v);
+    v = builder->addConstValue(2);
+    builder->beginRepeatLoop(v);
     {
-        v = m_builder->addConstValue("hello world");
-        m_builder->createListAppend(globalList1.get(), v);
+        v = builder->addConstValue("hello world");
+        builder->createListAppend(globalList1.get(), v);
 
-        v1 = m_builder->addConstValue(0);
-        v2 = m_builder->addConstValue(8.5);
-        m_builder->createListInsert(globalList2.get(), v1, v2);
+        v1 = builder->addConstValue(0);
+        v2 = builder->addConstValue(8.5);
+        builder->createListInsert(globalList2.get(), v1, v2);
 
-        v1 = m_builder->addConstValue(1);
-        v2 = m_builder->addConstValue(-4.25);
-        m_builder->createListReplace(localList.get(), v1, v2);
+        v1 = builder->addConstValue(1);
+        v2 = builder->addConstValue(-4.25);
+        builder->createListReplace(localList.get(), v1, v2);
     }
-    m_builder->endLoop();
+    builder->endLoop();
 
     checkLists();
 
     // repeat(0)
     resetLists();
 
-    v = m_builder->addConstValue(0);
-    m_builder->beginRepeatLoop(v);
+    v = builder->addConstValue(0);
+    builder->beginRepeatLoop(v);
     {
-        v = m_builder->addConstValue("hello world");
-        m_builder->createListAppend(globalList1.get(), v);
+        v = builder->addConstValue("hello world");
+        builder->createListAppend(globalList1.get(), v);
 
-        v1 = m_builder->addConstValue(0);
-        v2 = m_builder->addConstValue(8.5);
-        m_builder->createListInsert(globalList2.get(), v1, v2);
+        v1 = builder->addConstValue(0);
+        v2 = builder->addConstValue(8.5);
+        builder->createListInsert(globalList2.get(), v1, v2);
 
-        v1 = m_builder->addConstValue(1);
-        v2 = m_builder->addConstValue(-4.25);
-        m_builder->createListReplace(localList.get(), v1, v2);
+        v1 = builder->addConstValue(1);
+        v2 = builder->addConstValue(-4.25);
+        builder->createListReplace(localList.get(), v1, v2);
     }
-    m_builder->endLoop();
+    builder->endLoop();
 
     checkLists();
 
     // while (counter1 < 5) { ... until (counter2 == 3) {... counter2++ }; while (false) { ... }; counter1++ }
     resetLists();
 
-    v = m_builder->addConstValue(0);
-    m_builder->createVariableWrite(counter1.get(), v);
+    v = builder->addConstValue(0);
+    builder->createVariableWrite(counter1.get(), v);
 
-    m_builder->beginLoopCondition();
-    v1 = m_builder->addVariableValue(counter1.get());
-    v2 = m_builder->addConstValue(5);
-    v = m_builder->createCmpLT(v1, v2);
-    m_builder->beginWhileLoop(v);
+    builder->beginLoopCondition();
+    v1 = builder->addVariableValue(counter1.get());
+    v2 = builder->addConstValue(5);
+    v = builder->createCmpLT(v1, v2);
+    builder->beginWhileLoop(v);
     {
-        v = m_builder->addConstValue(0);
-        m_builder->createVariableWrite(counter2.get(), v);
-
-        m_builder->beginLoopCondition();
-        v1 = m_builder->addVariableValue(counter2.get());
-        v2 = m_builder->addConstValue(3);
-        v = m_builder->createCmpEQ(v1, v2);
-        m_builder->beginRepeatUntilLoop(v);
+        v = builder->addConstValue(0);
+        builder->createVariableWrite(counter2.get(), v);
+
+        builder->beginLoopCondition();
+        v1 = builder->addVariableValue(counter2.get());
+        v2 = builder->addConstValue(3);
+        v = builder->createCmpEQ(v1, v2);
+        builder->beginRepeatUntilLoop(v);
         {
-            v1 = m_builder->addConstValue(0);
-            v2 = m_builder->addConstValue(8.5);
-            m_builder->createListInsert(globalList2.get(), v1, v2);
-
-            v1 = m_builder->addConstValue(1);
-            v2 = m_builder->addConstValue(-4.25);
-            m_builder->createListReplace(localList.get(), v1, v2);
-
-            v1 = m_builder->addVariableValue(counter2.get());
-            v2 = m_builder->addConstValue(1);
-            v = m_builder->createAdd(v1, v2);
-            m_builder->createVariableWrite(counter2.get(), v);
+            v1 = builder->addConstValue(0);
+            v2 = builder->addConstValue(8.5);
+            builder->createListInsert(globalList2.get(), v1, v2);
+
+            v1 = builder->addConstValue(1);
+            v2 = builder->addConstValue(-4.25);
+            builder->createListReplace(localList.get(), v1, v2);
+
+            v1 = builder->addVariableValue(counter2.get());
+            v2 = builder->addConstValue(1);
+            v = builder->createAdd(v1, v2);
+            builder->createVariableWrite(counter2.get(), v);
         }
-        m_builder->endLoop();
+        builder->endLoop();
 
-        m_builder->beginLoopCondition();
-        v = m_builder->addConstValue(false);
-        m_builder->beginWhileLoop(v);
+        builder->beginLoopCondition();
+        v = builder->addConstValue(false);
+        builder->beginWhileLoop(v);
         {
-            v = m_builder->addConstValue("hello world");
-            m_builder->createListAppend(globalList1.get(), v);
+            v = builder->addConstValue("hello world");
+            builder->createListAppend(globalList1.get(), v);
         }
-        m_builder->endLoop();
+        builder->endLoop();
 
-        v1 = m_builder->addVariableValue(counter1.get());
-        v2 = m_builder->addConstValue(1);
-        v = m_builder->createAdd(v1, v2);
-        m_builder->createVariableWrite(counter1.get(), v);
+        v1 = builder->addVariableValue(counter1.get());
+        v2 = builder->addConstValue(1);
+        v = builder->createAdd(v1, v2);
+        builder->createVariableWrite(counter1.get(), v);
     }
-    m_builder->endLoop();
+    builder->endLoop();
 
     checkLists();
 
     // until (true)
     resetLists();
 
-    m_builder->beginLoopCondition();
-    v = m_builder->addConstValue(true);
-    m_builder->beginRepeatUntilLoop(v);
+    builder->beginLoopCondition();
+    v = builder->addConstValue(true);
+    builder->beginRepeatUntilLoop(v);
     {
-        v = m_builder->addConstValue("hello world");
-        m_builder->createListAppend(globalList1.get(), v);
+        v = builder->addConstValue("hello world");
+        builder->createListAppend(globalList1.get(), v);
 
-        v1 = m_builder->addConstValue(0);
-        v2 = m_builder->addConstValue(8.5);
-        m_builder->createListInsert(globalList2.get(), v1, v2);
+        v1 = builder->addConstValue(0);
+        v2 = builder->addConstValue(8.5);
+        builder->createListInsert(globalList2.get(), v1, v2);
 
-        v1 = m_builder->addConstValue(1);
-        v2 = m_builder->addConstValue(-4.25);
-        m_builder->createListReplace(localList.get(), v1, v2);
+        v1 = builder->addConstValue(1);
+        v2 = builder->addConstValue(-4.25);
+        builder->createListReplace(localList.get(), v1, v2);
     }
-    m_builder->endLoop();
+    builder->endLoop();
 
     checkLists();
 
@@ -2953,7 +2902,7 @@ TEST_F(LLVMCodeBuilderTest, LoopLists)
         "world\n"
         "false\n";
 
-    auto code = m_builder->build();
+    auto code = builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     ;
@@ -2969,8 +2918,8 @@ TEST_F(LLVMCodeBuilderTest, ListLoopTypeAnalysis)
     // This just makes sure the type analyzer is used correctly
     Stage stage;
     Sprite sprite;
-    sprite.setEngine(&m_engine);
-    EXPECT_CALL(m_engine, stage()).WillRepeatedly(Return(&stage));
+    sprite.setEngine(&m_utils.engine());
+    EXPECT_CALL(m_utils.engine(), stage()).WillRepeatedly(Return(&stage));
 
     auto globalList = std::make_shared<List>("", "");
     stage.addList(globalList);
@@ -2978,31 +2927,31 @@ TEST_F(LLVMCodeBuilderTest, ListLoopTypeAnalysis)
     auto localList = std::make_shared<List>("", "");
     sprite.addList(localList);
 
-    createBuilder(&sprite, true);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(&sprite, true);
 
-    m_builder->createListClear(localList.get());
+    builder->createListClear(localList.get());
 
-    CompilerValue *v = m_builder->addConstValue(5.25);
-    m_builder->createListAppend(localList.get(), v);
+    CompilerValue *v = builder->addConstValue(5.25);
+    builder->createListAppend(localList.get(), v);
 
-    v = m_builder->addConstValue(2);
-    m_builder->beginRepeatLoop(v);
+    v = builder->addConstValue(2);
+    builder->beginRepeatLoop(v);
     {
         // Type is unknown here because a string is added later
-        v = m_builder->createSub(m_builder->addListSize(localList.get()), m_builder->addConstValue(1));
-        v = m_builder->addListItem(localList.get(), v);
-        m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
+        v = builder->createSub(builder->addListSize(localList.get()), builder->addConstValue(1));
+        v = builder->addListItem(localList.get(), v);
+        builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
 
-        v = m_builder->addListItemIndex(localList.get(), m_builder->addConstValue(5.25));
-        m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
+        v = builder->addListItemIndex(localList.get(), builder->addConstValue(5.25));
+        builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
 
-        v = m_builder->addListContains(localList.get(), m_builder->addConstValue(5.25));
-        m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
+        v = builder->addListContains(localList.get(), builder->addConstValue(5.25));
+        builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v });
 
-        v = m_builder->addConstValue("test");
-        m_builder->createListAppend(localList.get(), v);
+        v = builder->addConstValue("test");
+        builder->createListAppend(localList.get(), v);
     }
-    m_builder->endLoop();
+    builder->endLoop();
 
     std::string expected =
         "5.25\n"
@@ -3012,7 +2961,7 @@ TEST_F(LLVMCodeBuilderTest, ListLoopTypeAnalysis)
         "0\n"
         "1\n";
 
-    auto code = m_builder->build();
+    auto code = builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     Thread thread(&sprite, nullptr, &script);
@@ -3025,19 +2974,19 @@ TEST_F(LLVMCodeBuilderTest, ListLoopTypeAnalysis)
 TEST_F(LLVMCodeBuilderTest, StopNoWarp)
 {
     Sprite sprite;
-    createBuilder(&sprite, false);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(&sprite, false);
 
-    m_builder->beginLoopCondition();
-    CompilerValue *v = m_builder->addConstValue(true);
-    m_builder->beginWhileLoop(v);
-    m_builder->createStop();
-    m_builder->endLoop();
+    builder->beginLoopCondition();
+    CompilerValue *v = builder->addConstValue(true);
+    builder->beginWhileLoop(v);
+    builder->createStop();
+    builder->endLoop();
 
-    m_builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
+    builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
 
     std::string expected = "";
 
-    auto code = m_builder->build();
+    auto code = builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     Thread thread(&sprite, nullptr, &script);
@@ -3050,18 +2999,18 @@ TEST_F(LLVMCodeBuilderTest, StopNoWarp)
 TEST_F(LLVMCodeBuilderTest, StopWarp)
 {
     Sprite sprite;
-    createBuilder(&sprite, true);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(&sprite, true);
 
-    CompilerValue *v = m_builder->addConstValue(true);
-    m_builder->beginIfStatement(v);
-    m_builder->createStop();
-    m_builder->endIf();
+    CompilerValue *v = builder->addConstValue(true);
+    builder->beginIfStatement(v);
+    builder->createStop();
+    builder->endIf();
 
-    m_builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
+    builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
 
     std::string expected = "";
 
-    auto code = m_builder->build();
+    auto code = builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     Thread thread(&sprite, nullptr, &script);
@@ -3074,14 +3023,14 @@ TEST_F(LLVMCodeBuilderTest, StopWarp)
 TEST_F(LLVMCodeBuilderTest, StopAndReturn)
 {
     Sprite sprite;
-    createBuilder(&sprite, true);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(&sprite, true);
 
-    m_builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
-    m_builder->createStop();
+    builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
+    builder->createStop();
 
     std::string expected = "no_args\n";
 
-    auto code = m_builder->build();
+    auto code = builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     Thread thread(&sprite, nullptr, &script);
@@ -3096,20 +3045,20 @@ TEST_F(LLVMCodeBuilderTest, MultipleScripts)
     Sprite sprite;
 
     // Script 1
-    createBuilder(&sprite, nullptr);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(&sprite, nullptr);
 
-    CompilerValue *v = m_builder->addConstValue("script1");
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    CompilerValue *v = builder->addConstValue("script1");
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    auto code1 = m_builder->build();
+    auto code1 = builder->build();
 
     // Script 2
-    createBuilder(&sprite, nullptr);
+    builder = m_utils.createBuilder(&sprite, nullptr);
 
-    v = m_builder->addConstValue("script2");
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addConstValue("script2");
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    auto code2 = m_builder->build();
+    auto code2 = builder->build();
 
     Script script1(&sprite, nullptr, nullptr);
     script1.setCode(code1);
@@ -3144,52 +3093,52 @@ TEST_F(LLVMCodeBuilderTest, Procedures)
     prototype1.setArgumentNames({ "any type 1", "any type 2", "bool" });
     prototype1.setArgumentIds({ "a", "b", "c" });
     prototype1.setWarp(false);
-    createBuilder(&sprite, &prototype1);
+    LLVMCodeBuilder *builder = m_utils.createBuilder(&sprite, &prototype1);
 
-    CompilerValue *v = m_builder->addConstValue(2);
-    m_builder->beginRepeatLoop(v);
-    m_builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
-    m_builder->endLoop();
+    CompilerValue *v = builder->addConstValue(2);
+    builder->beginRepeatLoop(v);
+    builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
+    builder->endLoop();
 
-    m_builder->createVariableWrite(var.get(), m_builder->addProcedureArgument("any type 1"));
-    m_builder->createListClear(list.get());
-    m_builder->createListAppend(list.get(), m_builder->addProcedureArgument("any type 2"));
+    builder->createVariableWrite(var.get(), builder->addProcedureArgument("any type 1"));
+    builder->createListClear(list.get());
+    builder->createListAppend(list.get(), builder->addProcedureArgument("any type 2"));
 
-    v = m_builder->addVariableValue(var.get());
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addVariableValue(var.get());
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addListItem(list.get(), m_builder->addConstValue(0));
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addListItem(list.get(), builder->addConstValue(0));
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    v = m_builder->addProcedureArgument("bool");
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
-    m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
+    v = builder->addProcedureArgument("bool");
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
 
-    v = m_builder->addProcedureArgument("invalid");
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addProcedureArgument("invalid");
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
-    m_builder->build();
+    builder->build();
 
     // Procedure 2
     BlockPrototype prototype2;
     prototype2.setProcCode("procedure 2");
     prototype2.setWarp(true);
-    createBuilder(&sprite, &prototype2);
+    builder = m_utils.createBuilder(&sprite, &prototype2);
 
-    v = m_builder->addConstValue(2);
-    m_builder->beginRepeatLoop(v);
-    m_builder->createProcedureCall(&prototype1, { m_builder->addConstValue(-652.3), m_builder->addConstValue(false), m_builder->addConstValue(true) });
-    m_builder->endLoop();
+    v = builder->addConstValue(2);
+    builder->beginRepeatLoop(v);
+    builder->createProcedureCall(&prototype1, { builder->addConstValue(-652.3), builder->addConstValue(false), builder->addConstValue(true) });
+    builder->endLoop();
 
-    m_builder->build();
+    builder->build();
 
     // Script
-    createBuilder(&sprite, false);
-    m_builder->createProcedureCall(&prototype1, { m_builder->addConstValue("test"), m_builder->addConstValue(true), m_builder->addConstValue(false) });
-    m_builder->createProcedureCall(&prototype2, {});
+    builder = m_utils.createBuilder(&sprite, false);
+    builder->createProcedureCall(&prototype1, { builder->addConstValue("test"), builder->addConstValue(true), builder->addConstValue(false) });
+    builder->createProcedureCall(&prototype2, {});
 
-    v = m_builder->addProcedureArgument("test");
-    m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
+    v = builder->addProcedureArgument("test");
+    builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
 
     std::string expected1 = "no_args\n";
 
@@ -3217,7 +3166,7 @@ TEST_F(LLVMCodeBuilderTest, Procedures)
         "0\n"
         "0\n";
 
-    auto code = m_builder->build();
+    auto code = builder->build();
     Script script(&sprite, nullptr, nullptr);
     script.setCode(code);
     Thread thread(&sprite, nullptr, &script);
@@ -3244,19 +3193,19 @@ TEST_F(LLVMCodeBuilderTest, HatPredicates)
     Sprite sprite;
 
     // Predicate 1
-    createPredicateBuilder(&sprite);
+    LLVMCodeBuilder *builder = m_utils.createPredicateBuilder(&sprite);
 
-    m_builder->addConstValue(true);
+    builder->addConstValue(true);
 
-    auto code1 = m_builder->build();
+    auto code1 = builder->build();
 
     // Predicate 2
-    createPredicateBuilder(&sprite);
+    builder = m_utils.createPredicateBuilder(&sprite);
 
-    CompilerValue *v = m_builder->addConstValue(false);
-    m_builder->addFunctionCall("test_const_bool", Compiler::StaticType::Bool, { Compiler::StaticType::Bool }, { v });
+    CompilerValue *v = builder->addConstValue(false);
+    builder->addFunctionCall("test_const_bool", Compiler::StaticType::Bool, { Compiler::StaticType::Bool }, { v });
 
-    auto code2 = m_builder->build();
+    auto code2 = builder->build();
 
     Script script1(&sprite, nullptr, nullptr);
     script1.setCode(code1);
@@ -3281,39 +3230,39 @@ TEST_F(LLVMCodeBuilderTest, Reporters)
     sprite.addVariable(var);
 
     // Reporter 1
-    createReporterBuilder(&sprite);
+    LLVMCodeBuilder *builder = m_utils.createReporterBuilder(&sprite);
 
-    m_builder->addConstValue(-45.23);
+    builder->addConstValue(-45.23);
 
-    auto code1 = m_builder->build();
+    auto code1 = builder->build();
 
     // Reporter 2
-    createReporterBuilder(&sprite);
+    builder = m_utils.createReporterBuilder(&sprite);
 
-    CompilerValue *v = m_builder->addConstValue("test");
-    m_builder->addFunctionCall("test_const_string", Compiler::StaticType::String, { Compiler::StaticType::String }, { v });
+    CompilerValue *v = builder->addConstValue("test");
+    builder->addFunctionCall("test_const_string", Compiler::StaticType::String, { Compiler::StaticType::String }, { v });
 
-    auto code2 = m_builder->build();
+    auto code2 = builder->build();
 
     // Reporter 3
-    createReporterBuilder(&sprite);
-    m_builder->addVariableValue(var.get());
+    builder = m_utils.createReporterBuilder(&sprite);
+    builder->addVariableValue(var.get());
 
-    auto code3 = m_builder->build();
+    auto code3 = builder->build();
 
     // Reporter 4
-    createReporterBuilder(&sprite);
+    builder = m_utils.createReporterBuilder(&sprite);
     int pointee;
-    m_builder->addConstValue(&pointee);
+    builder->addConstValue(&pointee);
 
-    auto code4 = m_builder->build();
+    auto code4 = builder->build();
 
     // Reporter 5
-    createReporterBuilder(&sprite);
-    v = m_builder->addConstValue(&pointee);
-    m_builder->addFunctionCall("test_const_pointer", Compiler::StaticType::Pointer, { Compiler::StaticType::Pointer }, { v });
+    builder = m_utils.createReporterBuilder(&sprite);
+    v = builder->addConstValue(&pointee);
+    builder->addFunctionCall("test_const_pointer", Compiler::StaticType::Pointer, { Compiler::StaticType::Pointer }, { v });
 
-    auto code5 = m_builder->build();
+    auto code5 = builder->build();
 
     auto runReporter = [&sprite](std::shared_ptr<ExecutableCode> code) {
         Script script(&sprite, nullptr, nullptr);
diff --git a/test/llvm/llvmtestutils.cpp b/test/llvm/llvmtestutils.cpp
index b57a8f52..24c0d580 100644
--- a/test/llvm/llvmtestutils.cpp
+++ b/test/llvm/llvmtestutils.cpp
@@ -199,6 +199,16 @@ Value LLVMTestUtils::getExpectedOpResult(OpType type, const Value &v1, const Val
     }
 }
 
+EngineMock &LLVMTestUtils::engine()
+{
+    return m_engine;
+}
+
+TargetMock &LLVMTestUtils::target()
+{
+    return m_target;
+}
+
 const RandomGeneratorMock &LLVMTestUtils::rng() const
 {
     return m_rng;
diff --git a/test/llvm/llvmtestutils.h b/test/llvm/llvmtestutils.h
index 0f677ed3..3080fc29 100644
--- a/test/llvm/llvmtestutils.h
+++ b/test/llvm/llvmtestutils.h
@@ -86,6 +86,8 @@ class LLVMTestUtils
         Value getExpectedOpResult(OpType type, const Value &v);
         Value getExpectedOpResult(OpType type, const Value &v1, const Value &v2);
 
+        EngineMock &engine();
+        TargetMock &target();
         const RandomGeneratorMock &rng() const;
 
     private:
