diff --git a/src/Lib/Script/Ast/IrOption.cc b/src/Lib/Script/Ast/IrOption.cc
index beabd87a987d5ecf2973b890f6fd00be55fb2959..78aec6976e6893923b72cea76ccca04a62d2a82c 100644
--- a/src/Lib/Script/Ast/IrOption.cc
+++ b/src/Lib/Script/Ast/IrOption.cc
@@ -1,9 +1,10 @@
 #include "IrOption.hh"
+#include "Lib/Script/FrontEnd/Lexer.hh"
 
 namespace Vivy::Script
 {
 IrOption::IrOption(StrV nameInModule) noexcept
-    : shapeName(nameInModule)
+    : moduleName(nameInModule)
 {
 }
 
@@ -32,12 +33,6 @@ IrOption::toString() const noexcept
     return "IrOption";
 }
 
-void
-IrOption::parse(std::vector<Token> *)
-{
-    throw std::logic_error("IrOption");
-}
-
 IrOption *
 IrOption::empty() noexcept
 {
@@ -90,4 +85,50 @@ IrOption::match(const std::vector<IrOption *> &others) const noexcept
                            return this->match(shape);
                        });
 }
+
+void
+IrOption::parse(std::vector<Token> *tokens)
+{
+    const Token firstDeclToken = getInnerTokenOpt(tokenListPop(tokens));
+    firstDeclToken.assertTypeSimple(TOKEN_OPTION);
+
+    const Token shapeNameToken = getInnerTokenOpt(tokenListPop(tokens));
+    shapeNameToken.assertType(Token::Type::QNAME);
+    shapeName = shapeNameToken.asQName();
+
+    getInnerTokenOpt(tokenListPop(tokens)).assertTypeSimple(TOKEN_CURLY_BRACKET_LEFT);
+
+    if (getInnerTokenOpt(tokenListPeek(tokens)).isSimple(TOKEN_CURLY_BRACKET_RIGHT)) {
+        throw std::runtime_error(firstDeclToken.location().toString() +
+                                 ": Empty option groups are not supported!");
+    }
+
+    /* ... | name : type = value */
+    while (getInnerTokenOpt(tokenListPeek(tokens)).isQName()) {
+        const Token fieldNameToken = getInnerTokenOpt(tokenListPop(tokens));
+        getInnerTokenOpt(tokenListPop(tokens)).assertTypeSimple(TOKEN_COL);
+        const Token typeNameToken = getInnerTokenOpt(tokenListPop(tokens));
+        typeNameToken.assertType(Token::Type::SIMPLE);
+        getInnerTokenOpt(tokenListPop(tokens)).assertTypeSimple(TOKEN_ASSIGN);
+        const Token defaultValueToken = getInnerTokenOpt(tokenListPop(tokens));
+
+        std::cerr << "Found option: " << shapeName.toStdString() << "."
+                  << fieldNameToken.asQName().toStdString() << " : "
+                  << typeNameToken.asSimple().toStdString() << " = " << defaultValueToken.toString()
+                  << ";\n";
+
+        const Token continuationToken = getInnerTokenOpt(tokenListPop(tokens));
+        if (continuationToken.isSimple(TOKEN_COMMA))
+            continue;
+        else if (continuationToken.isSimple(TOKEN_CURLY_BRACKET_RIGHT))
+            break;
+        else {
+            throw std::runtime_error(
+                firstDeclToken.location().toString() +
+                ": invalid option declaration, to separate fields in the option you "
+                "must use a comma. Found unexpected token: " +
+                continuationToken.toString());
+        }
+    }
+}
 }
diff --git a/src/Lib/Script/Ast/IrOption.hh b/src/Lib/Script/Ast/IrOption.hh
index c7389bb6a190e8746beb43181673eef7225ab82f..6e4fae6d57bbc1b27a2ddf178ccc2527929ad764 100644
--- a/src/Lib/Script/Ast/IrOption.hh
+++ b/src/Lib/Script/Ast/IrOption.hh
@@ -22,8 +22,9 @@ class IrOption final : public IrElement {
         const Content content;
     };
 
+    const StrV moduleName;
     bool optionIsEmpty = true;
-    const StrV shapeName;
+    StrV shapeName     = STRV_NULL;
     std::vector<ShapeElement *> shapes;
 
     void addShape(const IrModule *module, const ShapeElement::Content &content) noexcept;