diff --git a/src/Lib/Script/Ast/IrExpression.cc b/src/Lib/Script/Ast/IrExpression.cc
index f2111cdd6085557966c7a0f19fe316cf9e9edc2f..ff8fd6093c8782f1e11e507a68117598c99819a7 100644
--- a/src/Lib/Script/Ast/IrExpression.cc
+++ b/src/Lib/Script/Ast/IrExpression.cc
@@ -44,8 +44,14 @@ IrExpression::toString() const noexcept
     assert(false && "Unreachable");
 }
 
+bool
+IrExpression::isInfixOperator() const noexcept
+{
+    return (type() == Type::CompOp) || (type() == Type::ArithmeticOp) || (type() == Type::LogicOp);
+}
+
 void
-IrExpression::parse(std::vector<Token> *tokens)
+IrExpression::parse(std::vector<Token> *argTokens)
 {
 #include "Parser/IrExpression.hh"
 }
diff --git a/src/Lib/Script/Ast/IrExpression.hh b/src/Lib/Script/Ast/IrExpression.hh
index 6f92db8ad7cff25bc52123738cccb786b2ccfdeb..c62ddd11352ce57810c25b5bac3d560b38c57b49 100644
--- a/src/Lib/Script/Ast/IrExpression.hh
+++ b/src/Lib/Script/Ast/IrExpression.hh
@@ -6,6 +6,10 @@
 
 namespace Vivy::Script
 {
+#define VIVY_IR_EXPRESSION(clazz) \
+    VIVY_IR_ELEMENT(clazz)        \
+    friend class IrExpression;
+
 class IrExpression : public IrElement {
     VIVY_IR_ELEMENT(IrExpression)
 
@@ -27,11 +31,12 @@ public:
     void parse(std::vector<Token> *);
 
     Type type() const noexcept;
+    bool isInfixOperator() const noexcept;
     virtual IrType *innerType() const noexcept;
 };
 
 class IrEConstExpr : public IrExpression {
-    VIVY_IR_ELEMENT(IrEConstExpr)
+    VIVY_IR_EXPRESSION(IrEConstExpr)
 
     IrEConstExpr(const Token &);
 
@@ -56,7 +61,7 @@ public:
 };
 
 class IrECall : public IrExpression {
-    VIVY_IR_ELEMENT(IrECall)
+    VIVY_IR_EXPRESSION(IrECall)
 
     IrFunction *callPtr = nullptr;
     std::vector<IrExpression *> inArgs;
@@ -69,7 +74,7 @@ public:
 };
 
 class IrECompOp : public IrExpression {
-    VIVY_IR_ELEMENT(IrECompOp)
+    VIVY_IR_EXPRESSION(IrECompOp)
 
 public:
     enum class OpType { LT, GT, LE, GE, EQ, NEQ };
@@ -88,7 +93,7 @@ public:
 };
 
 class IrEArithmeticOp : public IrExpression {
-    VIVY_IR_ELEMENT(IrEArithmeticOp)
+    VIVY_IR_EXPRESSION(IrEArithmeticOp)
 
 public:
     enum class OpType { Add, Sub, Mul, Div, Mod };
@@ -107,7 +112,7 @@ public:
 };
 
 class IrELogicOp : public IrExpression {
-    VIVY_IR_ELEMENT(IrELogicOp)
+    VIVY_IR_EXPRESSION(IrELogicOp)
 
 public:
     enum class OpType { And, Or, Xor };
@@ -126,7 +131,7 @@ public:
 };
 
 class IrEVariableRef : public IrExpression {
-    VIVY_IR_ELEMENT(IrEVariableRef)
+    VIVY_IR_EXPRESSION(IrEVariableRef)
 
     IrVariable *const referencedVariable;
     std::vector<IrExpression *> indicies;
diff --git a/src/Lib/Script/Ast/Parser/IrExpression.hh b/src/Lib/Script/Ast/Parser/IrExpression.hh
index 57bcbd04f159a56da4ed0783af1c007e30ad011a..ab380e221c679c9c064fe8de85517d137ba44ad3 100644
--- a/src/Lib/Script/Ast/Parser/IrExpression.hh
+++ b/src/Lib/Script/Ast/Parser/IrExpression.hh
@@ -1,3 +1,80 @@
 /* In: std::vector<Token>* tokens */
 
+auto throwUnexpectedToken = [](const Token &tok) {
+    throw std::runtime_error("Unexpected token in location " + tok.location().toString() + ": " +
+                             tok.toString());
+};
+
+auto updateExprWithConstExpr = [](IrExpression *&current, Token tok) -> void {
+    IrExpression *newLeft = IrElement::create<IrEConstExpr>(current, tok);
+    /* (... `op` <- currentExpression) newLeft -> currentExpression */
+    if (current != nullptr) {
+        switch (current->type()) {
+        case Type::CompOp: dynamic_cast<IrECompOp *>(current)->left = newLeft; return;
+        case Type::ArithmeticOp: dynamic_cast<IrEArithmeticOp *>(current)->left = newLeft; return;
+        case Type::LogicOp: dynamic_cast<IrELogicOp *>(current)->left = newLeft; return;
+        case Type::ConstExpr:
+        case Type::Call:
+        case Type::VariableRef: throw std::runtime_error("Invalid expression");
+        }
+    }
+
+    /* newLeft -> currentExpression */
+    else
+        current = newLeft;
+};
+
+volatile ssize_t expressionScopeLevel = 0;
+
+/*
+** a + b + c + d + e ==> (e + (d + (c + (b + a))))
+** first : simple
+** find op, parse the next token
+** parse tokens => new expr, take current, add to left
+*/
+
+auto parseNextExpression = [&expressionScopeLevel, updateExprWithConstExpr](
+                               std::vector<Token> *tokens, auto &itSelf) -> IrExpression * {
+    const ssize_t expressionScopeLevelAtLaunchTime = expressionScopeLevel;
+    IrExpression *currentExpression                = nullptr;
+
+    while (tokenListIsNotEmpty(tokens) &&
+           (expressionScopeLevelAtLaunchTime < expressionScopeLevel)) {
+        const std::optional<Token> maybeFirstToken = tokenListPeek(tokens);
+        if (!maybeFirstToken.has_value())
+            return nullptr;
+        const Token firstToken = getInnerTokenOpt(maybeFirstToken);
+
+        switch (firstToken.valueType()) {
+        case Token::Type::QNAME: {
+            // Function Call or Variable Ref
+            throw std::logic_error("QNAME not handled (call or var)");
+            break;
+        }
+
+        case Token::Type::COLORLIT:
+        case Token::Type::INTEGER:
+        case Token::Type::FLOATING:
+        case Token::Type::STRINGLIT: {
+            updateExprWithConstExpr(currentExpression, firstToken);
+            break;
+        }
+
+        case Token::Type::SIMPLE: {
+            if (firstToken.isSimple(TOKEN_TRUE) || firstToken.isSimple(TOKEN_FALSE)) {
+                updateExprWithConstExpr(currentExpression, firstToken);
+            }
+
+            else {
+                // operation -> new current, add old into right
+            }
+            break;
+        }
+        }
+    }
+
+    return currentExpression;
+};
+
+parseNextExpression(argTokens, parseNextExpression);
 throw std::logic_error("Parser/IrExpression: Not implemented");
diff --git a/src/Lib/Script/Ast/Parser/IrInstruction.hh b/src/Lib/Script/Ast/Parser/IrInstruction.hh
index f3f3810d4d72965da1c9f26f3c3d3b22b796726d..7436ec6d9ba516638f4a3b47a817fd98bf0146a6 100644
--- a/src/Lib/Script/Ast/Parser/IrInstruction.hh
+++ b/src/Lib/Script/Ast/Parser/IrInstruction.hh
@@ -28,6 +28,7 @@ auto parseNextInstruction = [&instructionScopeLevel](
                                 auto &itSelf                /* The lambda itself, for recursion */
                             ) {
     if (tokenListIsEmpty(tokens)) {
+        throw std::runtime_error("Implement void instruction");
         /* Create a `return void` instruction */
     }