Repository: CrossGL/crosstl

Issue:
Adding support for Vulkan backend

Hints from issue comments:
@he11owthere: Would love to work on this.@NripeshN: Hi @he11owthere 
I have assigned this issue to you, feel free to work on it😁

Solution patch:
diff --git a/.github/workflows/backend-tests.yml b/.github/workflows/backend-tests.yml
index dcc94f3b..82317026 100644
--- a/.github/workflows/backend-tests.yml
+++ b/.github/workflows/backend-tests.yml
@@ -13,8 +13,8 @@ jobs:
     runs-on: ${{ matrix.OS }}
     strategy:
       matrix:
-        backend: [directx, metal, opengl] # ToDO: Add mojo to the list
-        python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
+        backend: [directx, metal, opengl, 'slang'] # ToDO: Add mojo to the list
+        python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
         OS: [ubuntu-latest, windows-latest, macOS-latest]
       fail-fast: false
 
diff --git a/.github/workflows/translator-tests.yml b/.github/workflows/translator-tests.yml
index 36ccd232..b183139c 100644
--- a/.github/workflows/translator-tests.yml
+++ b/.github/workflows/translator-tests.yml
@@ -13,8 +13,8 @@ jobs:
     runs-on: ${{ matrix.OS }}
     strategy:
       matrix:
-        component: ['directx', 'metal', 'opengl', 'general']  # ToDo: Add 'mojo' to the list
-        python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
+        component: ['directx', 'metal', 'opengl', 'slang' ,'general']  # ToDo: Add 'mojo' to the list
+        python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
         OS: [ubuntu-latest, windows-latest, macOS-latest]
       fail-fast: false
 
diff --git a/.gitignore b/.gitignore
index d679f837..25c926f3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,3 +41,7 @@ build
 /compiler/__pycache__
 *:Z*
 *workspace
+
+# Python
+crosstl.egg-info
+.vscode/settings.json
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index cb862fb4..87c77365 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,4 +1,3 @@
-
 # 🚀 Contribution Guidelines
 
 Thank you for your interest in contributing to **CrossTL**! By contributing, you help improve the project and make it more robust and useful for everyone. 🎉
@@ -62,6 +61,24 @@ git push origin feature-name
 
 Open a pull request on the original repository. Provide a detailed description of your changes, why they are necessary, and any additional information that may be useful for the reviewers.
 
+### 🔖 Assigning or Creating Issues
+
+If you're looking for something to work on, check out the open issues on our repository! You can assign yourself to an issue by simply commenting:
+
+```plaintext
+@CrossGL-issue-bot assign me
+```
+
+The bot will automatically assign the issue to you.
+
+If you'd like to propose a new feature or identify a bug that you'd like to work on, you can create a new issue. Provide as much detail as possible in the issue description, then comment on it with:
+
+```plaintext
+@CrossGL-issue-bot assign me
+```
+
+This makes it easy for contributors to collaborate and track who is working on what. 🎯
+
 ## Contribution Pipeline
 
 ### 🐛 Issue Tracking
diff --git a/README.md b/README.md
index f4f24657..0ea36490 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
 <div style="display: block;" align="center">
-    <img class="only-dark" width="10%" height="10%" src="https://crossgl.github.io/_static/logo.png#gh-dark-mode-only"/>
+    <img class="only-dark" width="10%" height="10%" src="https://github.com/CrossGL/crossgl-docs/blob/main/docs/assets/logo.png#gh-dark-mode-only"/>
 </div>
 
 
@@ -8,19 +8,19 @@
 <div style="display: block;" align="center">
     <img class="dark-light" width="5%" >
     <a href="https://crossgl.net/">
-        <img class="dark-light" height="5%" width="5%" src="https://github.com/samthakur587/docs2.0/blob/main/web_icon.png">
+        <img class="dark-light" height="5%" width="5%" src="https://github.com/CrossGL/crossgl-docs/blob/main/docs/assets/web_icon.png">
     </a>
     <img class="dark-light" width="5%" >
-    <a href="https://crossgl.github.io/language.html">
-        <img class="dark-light" height="5%" width="5%" src="https://github.com/samthakur587/docs2.0/blob/main/docs.png">
+    <a href="https://crossgl.github.io/crossgl-docs/language.html">
+        <img class="dark-light" height="5%" width="5%" src="https://github.com/CrossGL/crossgl-docs/blob/main/docs/assets/docs.png">
     </a>
     <img class="dark-light" width="5%" >
     <a href="https://github.com/CrossGL/demos">
-        <img class="dark-light" height="5%" width="5%" src="https://github.com/samthakur587/docs2.0/blob/main/written.png">
+        <img class="dark-light" height="5%" width="5%" src="https://github.com/CrossGL/crossgl-docs/blob/main/docs/assets/written.png">
     </a>
     <img class="dark-light" width="5%" >
-    <a href="https://crossgl.github.io/design.html">
-        <img class="dark-light" height="5%" width="5%" src="https://github.com/samthakur587/docs2.0/blob/main/strategic-plan.png">
+    <a href="https://crossgl.github.io/crossgl-docs/design.html">
+        <img class="dark-light" height="5%" width="5%" src="https://github.com/CrossGL/crossgl-docs/blob/main/docs/assets/strategic-plan.png">
     </a>
 </div>
 
diff --git a/crosstl/src/backend/DirectX/DirectxAst.py b/crosstl/src/backend/DirectX/DirectxAst.py
index b314f058..ac88d52b 100644
--- a/crosstl/src/backend/DirectX/DirectxAst.py
+++ b/crosstl/src/backend/DirectX/DirectxAst.py
@@ -86,6 +86,24 @@ def __repr__(self):
         return f"ForNode(init={self.init}, condition={self.condition}, update={self.update}, body={self.body})"
 
 
+class WhileNode(ASTNode):
+    def __init__(self, condition, body):
+        self.condition = condition
+        self.body = body
+
+    def __repr__(self):
+        return f"WhileNode(condition={self.condition}, body={self.body})"
+
+
+class DoWhileNode(ASTNode):
+    def __init__(self, condition, body):
+        self.condition = condition
+        self.body = body
+
+    def __repr__(self):
+        return f"DoWhileNode(condition={self.condition}, body={self.body})"
+
+
 class ReturnNode(ASTNode):
     def __init__(self, value):
         self.value = value
diff --git a/crosstl/src/backend/DirectX/DirectxCrossGLCodeGen.py b/crosstl/src/backend/DirectX/DirectxCrossGLCodeGen.py
index 92f02b53..04a4b632 100644
--- a/crosstl/src/backend/DirectX/DirectxCrossGLCodeGen.py
+++ b/crosstl/src/backend/DirectX/DirectxCrossGLCodeGen.py
@@ -140,6 +140,10 @@ def generate_function_body(self, body, indent=0, is_main=False):
                     code += f"return {self.generate_expression(stmt.value, is_main)};\n"
             elif isinstance(stmt, ForNode):
                 code += self.generate_for_loop(stmt, indent, is_main)
+            elif isinstance(stmt, WhileNode):
+                code += self.generate_while_loop(stmt, indent, is_main)
+            elif isinstance(stmt, DoWhileNode):
+                code += self.generate_do_while_loop(stmt, indent, is_main)
             elif isinstance(stmt, IfNode):
                 code += self.generate_if_statement(stmt, indent, is_main)
         return code
@@ -154,6 +158,23 @@ def generate_for_loop(self, node, indent, is_main):
         code += "    " * indent + "}\n"
         return code
 
+    def generate_while_loop(self, node, indent, is_main):
+        condition = self.generate_expression(node.condition, is_main)
+
+        code = f"while ({condition}) {{\n"
+        code += self.generate_function_body(node.body, indent + 1, is_main)
+        code += "    " * indent + "}\n"
+        return code
+
+    def generate_do_while_loop(self, node, indent, is_main):
+        condition = self.generate_expression(node.condition, is_main)
+
+        code = "do {\n"
+        code += self.generate_function_body(node.body, indent + 1, is_main)
+        code += "    " * indent + "} "
+        code += f"while ({condition});\n"
+        return code
+
     def generate_if_statement(self, node, indent, is_main):
         condition = self.generate_expression(node.condition, is_main)
 
diff --git a/crosstl/src/backend/DirectX/DirectxLexer.py b/crosstl/src/backend/DirectX/DirectxLexer.py
index c42565b8..a2c6084f 100644
--- a/crosstl/src/backend/DirectX/DirectxLexer.py
+++ b/crosstl/src/backend/DirectX/DirectxLexer.py
@@ -19,6 +19,8 @@
     ("ELSE_IF", r"\belse\sif\b"),
     ("ELSE", r"\belse\b"),
     ("FOR", r"\bfor\b"),
+    ("WHILE", r"\b\while\b"),
+    ("DO", r"\b\do\b"),
     ("REGISTER", r"\bregister\b"),
     ("IDENTIFIER", r"[a-zA-Z_][a-zA-Z0-9_]*"),
     ("NUMBER", r"\d+(\.\d+)?"),
@@ -32,6 +34,8 @@
     ("COMMA", r","),
     ("COLON", r":"),
     ("QUESTION", r"\?"),
+    ("SHIFT_LEFT", r"<<"),
+    ("SHIFT_RIGHT", r">>"),
     ("LESS_EQUAL", r"<="),
     ("GREATER_EQUAL", r">="),
     ("LESS_THAN", r"<"),
@@ -44,8 +48,11 @@
     ("DIVIDE_EQUALS", r"/="),
     ("ASSIGN_XOR", r"\^="),
     ("ASSIGN_OR", r"\|="),
+    ("ASSIGN_AND", r"\&="),
+    ("BITWISE_XOR", r"\^"),
     ("AND", r"&&"),
     ("OR", r"\|\|"),
+    ("BITWISE_OR", r"\|"),
     ("DOT", r"\."),
     ("MULTIPLY", r"\*"),
     ("DIVIDE", r"/"),
@@ -72,6 +79,8 @@
     "if": "IF",
     "else": "ELSE",
     "for": "FOR",
+    "while": "WHILE",
+    "do": "DO",
     "register": "REGISTER",
 }
 
diff --git a/crosstl/src/backend/DirectX/DirectxParser.py b/crosstl/src/backend/DirectX/DirectxParser.py
index 61fd5447..c3cd409d 100644
--- a/crosstl/src/backend/DirectX/DirectxParser.py
+++ b/crosstl/src/backend/DirectX/DirectxParser.py
@@ -2,6 +2,8 @@
     AssignmentNode,
     BinaryOpNode,
     ForNode,
+    WhileNode,
+    DoWhileNode,
     FunctionCallNode,
     FunctionNode,
     IfNode,
@@ -195,6 +197,10 @@ def parse_statement(self):
             return self.parse_for_statement()
         elif self.current_token[0] == "RETURN":
             return self.parse_return_statement()
+        elif self.current_token[0] == "WHILE":
+            return self.parse_while_statement()
+        elif self.current_token[0] == "DO":
+            return self.parse_do_while_statement()
         else:
             return self.parse_expression_statement()
 
@@ -231,6 +237,11 @@ def parse_variable_declaration_or_assignment(self):
                     "DIVIDE_EQUALS",
                     "ASSIGN_XOR",
                     "ASSIGN_OR",
+                    "ASSIGN_AND",
+                    "SHIFT_LEFT",
+                    "SHIFT_RIGHT",
+                    "BITWISE_OR",
+                    "BITWISE_XOR",
                 ]:
                     # Handle assignment operators (e.g., =, +=, -=, ^=, etc.)
                     op = self.current_token[1]
@@ -247,6 +258,11 @@ def parse_variable_declaration_or_assignment(self):
                 "DIVIDE_EQUALS",
                 "ASSIGN_XOR",
                 "ASSIGN_OR",
+                "ASSIGN_AND",
+                "SHIFT_LEFT",
+                "SHIFT_RIGHT",
+                "BITWISE_OR",
+                "BITWISE_XOR",
             ]:
                 # Handle assignment operators (e.g., =, +=, -=, ^=, etc.)
                 op = self.current_token[1]
@@ -266,6 +282,11 @@ def parse_variable_declaration_or_assignment(self):
                     "DIVIDE_EQUALS",
                     "ASSIGN_XOR",
                     "ASSIGN_OR",
+                    "ASSIGN_AND",
+                    "SHIFT_LEFT",
+                    "SHIFT_RIGHT",
+                    "BITWISE_OR",
+                    "BITWISE_XOR",
                 ]:
                     op = self.current_token[1]
                     self.eat(self.current_token[0])
@@ -340,6 +361,35 @@ def parse_for_statement(self):
 
         return ForNode(init, condition, update, body)
 
+    def parse_while_statement(self):
+        self.eat("WHILE")
+        self.eat("LPAREN")
+
+        # Parse condition
+        condition = self.parse_expression()
+        self.eat("RPAREN")
+
+        # Parse body
+        body = self.parse_block()
+
+        return WhileNode(condition, body)
+
+    def parse_do_while_statement(self):
+        # do token
+        self.eat("DO")
+
+        # parse do block
+        body = self.parse_block()
+
+        # parse while condition
+        self.eat("WHILE")
+        self.eat("LPAREN")
+        condition = self.parse_expression()
+        self.eat("RPAREN")
+        self.eat("SEMICOLON")
+
+        return DoWhileNode(condition, body)
+
     def parse_return_statement(self):
         self.eat("RETURN")
         value = self.parse_expression()
@@ -364,6 +414,11 @@ def parse_assignment(self):
             "DIVIDE_EQUALS",
             "ASSIGN_XOR",
             "ASSIGN_OR",
+            "ASSIGN_AND",
+            "SHIFT_LEFT",
+            "SHIFT_RIGHT",
+            "BITWISE_OR",
+            "BITWISE_XOR",
         ]:
             op = self.current_token[1]
             self.eat(self.current_token[0])
@@ -402,9 +457,12 @@ def parse_relational(self):
         left = self.parse_additive()
         while self.current_token[0] in [
             "LESS_THAN",
+            "SHIFT_LEFT",
+            "SHIFT_RIGHT",
             "GREATER_THAN",
             "LESS_EQUAL",
             "GREATER_EQUAL",
+            "BITWISE_XOR",
         ]:
             op = self.current_token[1]
             self.eat(self.current_token[0])
diff --git a/crosstl/src/backend/Vulkan/VulkanAst.py b/crosstl/src/backend/Vulkan/VulkanAst.py
new file mode 100644
index 00000000..67e9948e
--- /dev/null
+++ b/crosstl/src/backend/Vulkan/VulkanAst.py
@@ -0,0 +1,258 @@
+class ASTNode:
+    pass
+
+
+class TernaryOpNode:
+    def __init__(self, condition, true_expr, false_expr):
+        self.condition = condition
+        self.true_expr = true_expr
+        self.false_expr = false_expr
+
+    def __repr__(self):
+        return f"TernaryOpNode(condition={self.condition}, true_expr={self.true_expr}, false_expr={self.false_expr})"
+
+
+class ShaderNode:
+    def __init__(
+        self,
+        spirv_version,
+        descriptor_sets,
+        shader_stages,
+        functions,
+    ):
+        self.spirv_version = spirv_version
+        self.descriptor_sets = descriptor_sets
+        self.shader_stages = shader_stages
+        self.functions = functions
+
+    def __repr__(self):
+        return f"ShaderNode(spirv_version={self.spirv_version}, descriptor_sets={self.descriptor_sets}, shader_stages={self.shader_stages}, functions={self.functions})"
+
+
+class IfNode(ASTNode):
+    def __init__(
+        self,
+        if_condition,
+        if_body,
+        else_if_conditions=[],
+        else_if_bodies=[],
+        else_body=None,
+    ):
+        self.if_condition = if_condition
+        self.if_body = if_body
+        self.else_if_conditions = else_if_conditions
+        self.else_if_bodies = else_if_bodies
+        self.else_body = else_body
+
+    def __repr__(self):
+        return f"IfNode(if_condition={self.if_condition}, if_body={self.if_body}, else_if_conditions={self.else_if_conditions}, else_if_bodies={self.else_if_bodies}, else_body={self.else_body})"
+
+
+class ForNode(ASTNode):
+    def __init__(self, init, condition, update, body):
+        self.init = init
+        self.condition = condition
+        self.update = update
+        self.body = body
+
+    def __repr__(self):
+        return f"ForNode(init={self.init}, condition={self.condition}, update={self.update}, body={self.body})"
+
+
+class ReturnNode(ASTNode):
+    def __init__(self, value):
+        self.value = value
+
+    def __repr__(self):
+        return f"ReturnNode(value={self.value})"
+
+
+class FunctionCallNode(ASTNode):
+    def __init__(self, name, args):
+        self.name = name
+        self.args = args
+
+    def __repr__(self):
+        return f"FunctionCallNode(name={self.name}, args={self.args})"
+
+
+class BinaryOpNode(ASTNode):
+    def __init__(self, left, op, right):
+        self.left = left
+        self.op = op
+        self.right = right
+
+    def __repr__(self):
+        return f"BinaryOpNode(left={self.left}, op={self.op}, right={self.right})"
+
+
+class UnaryOpNode(ASTNode):
+    def __init__(self, op, operand):
+        self.op = op
+        self.operand = operand
+
+    def __repr__(self):
+        return f"UnaryOpNode(operator={self.op}, operand={self.operand})"
+
+
+class DescriptorSetNode(ASTNode):
+    def __init__(self, set_number, bindings):
+        self.set_number = set_number
+        self.bindings = bindings
+
+    def __repr__(self):
+        return (
+            f"DescriptorSetNode(set_number={self.set_number}, bindings={self.bindings})"
+        )
+
+
+class LayoutNode(ASTNode):
+    def __init__(
+        self,
+        bindings,
+        push_constant,
+        layout_type,
+        data_type,
+        variable_name,
+        struct_fields,
+    ):
+        self.bindings = bindings
+        self.push_constant = push_constant
+        self.layout_type = layout_type
+        self.data_type = data_type
+        self.variable_name = variable_name
+        self.struct_fields = struct_fields
+
+    def __repr__(self):
+        return (
+            f"LayoutNode(bindings={self.bindings}, push_constant={self.push_constant}, "
+            f"layout_type={self.layout_type}, data_type={self.data_type}, "
+            f"variable_name={self.variable_name}, struct_fields={self.struct_fields})"
+        )
+
+
+class UniformNode(ASTNode):
+    def __init__(self, name, var_type, value=None):
+        self.name = name
+        self.var_type = var_type
+        self.value = value
+
+    def __repr__(self):
+        return f"UniformNode(name={self.name}, var_type={self.var_type}, value={self.value})"
+
+
+class ShaderStageNode(ASTNode):
+    def __init__(self, stage, entry_point):
+        self.stage = stage
+        self.entry_point = entry_point
+
+    def __repr__(self):
+        return f"ShaderStageNode(stage={self.stage}, entry_point={self.entry_point})"
+
+
+class PushConstantNode(ASTNode):
+    def __init__(self, size, values):
+        self.size = size
+        self.values = values
+
+    def __repr__(self):
+        return f"PushConstantNode(size={self.size}, values={self.values})"
+
+
+class StructNode(ASTNode):
+    def __init__(self, name, members):
+        self.name = name
+        self.members = members
+
+    def __repr__(self):
+        return f"StructNode(name={self.name}, members={self.members})"
+
+
+class FunctionNode(ASTNode):
+    def __init__(self, name, return_type, parameters, body):
+        self.name = name
+        self.return_type = return_type
+        self.parameters = parameters
+        self.body = body
+
+    def __repr__(self):
+        return f"FunctionNode(name={self.name}, return_type={self.return_type}, parameters={self.parameters}, body={self.body})"
+
+
+class MemberAccessNode(ASTNode):
+    def __init__(self, object, member):
+        self.object = object
+        self.member = member
+
+    def __repr__(self):
+        return f"MemberAccessNode(object={self.object}, member={self.member})"
+
+
+class VariableNode(ASTNode):
+    def __init__(self, name, var_type):
+        self.name = name
+        self.var_type = var_type
+
+    def __repr__(self):
+        return f"VariableNode(name={self.name}, var_type={self.var_type})"
+
+
+class SwitchNode(ASTNode):
+    def __init__(self, expression, cases):
+        self.expression = expression
+        self.cases = cases
+
+    def __repr__(self):
+        return f"SwitchNode(expression={self.expression}, cases={self.cases})"
+
+
+class CaseNode(ASTNode):
+    def __init__(self, value, body):
+        self.value = value
+        self.body = body
+
+    def __repr__(self):
+        return f"CaseNode(value={self.value}, body={self.body})"
+
+
+class DefaultNode(ASTNode):
+    def __init__(self, statements):
+        self.statements = statements
+
+    def __repr__(self):
+        return f"DefaultNode(statements={self.statements})"
+
+
+class WhileNode(ASTNode):
+    def __init__(self, condition, body):
+        self.condition = condition
+        self.body = body
+
+    def __repr__(self):
+        return f"WhileNode(condition={self.condition}, body={self.body})"
+
+
+class DoWhileNode(ASTNode):
+    def __init__(self, body, condition):
+        self.body = body
+        self.condition = condition
+
+    def __repr__(self):
+        return f"DoWhileNode(body={self.body}, condition={self.condition})"
+
+
+class AssignmentNode(ASTNode):
+    def __init__(self, name, value):
+        self.name = name
+        self.value = value
+
+    def __repr__(self):
+        return f"AssignmentNode(name={self.name}, value={self.value})"
+
+
+class BreakNode(ASTNode):
+    def __init__(self):
+        pass
+
+    def __repr__(self):
+        return f"BreakNode()"
diff --git a/crosstl/src/backend/Vulkan/VulkanLexer.py b/crosstl/src/backend/Vulkan/VulkanLexer.py
new file mode 100644
index 00000000..471ab723
--- /dev/null
+++ b/crosstl/src/backend/Vulkan/VulkanLexer.py
@@ -0,0 +1,177 @@
+import re
+
+TOKENS = [
+    ("COMMENT_SINGLE", r"//.*"),
+    ("COMMENT_MULTI", r"/\*[\s\S]*?\*/"),
+    ("WHITESPACE", r"\s+"),
+    ("SEMANTIC", r":\w+"),
+    ("PRE_INCREMENT", r"\+\+(?=\w)"),
+    ("PRE_DECREMENT", r"--(?=\w)"),
+    ("POST_INCREMENT", r"(?<=\w)\+\+"),
+    ("POST_DECREMENT", r"(?<=\w)--"),
+    ("IDENTIFIER", r"[a-zA-Z_][a-zA-Z0-9_]*"),
+    ("NUMBER", r"\d+(\.\d*)?|\.\d+"),
+    ("SEMICOLON", r";"),
+    ("LBRACE", r"\{"),
+    ("RBRACE", r"\}"),
+    ("LPAREN", r"\("),
+    ("RPAREN", r"\)"),
+    ("COMMA", r","),
+    ("DOT", r"\."),
+    ("EQUAL", r"=="),
+    ("ASSIGN_AND", r"&="),
+    ("ASSIGN_OR", r"\|="),
+    ("ASSIGN_XOR", r"\^="),
+    ("PLUS_EQUALS", r"\+="),
+    ("MINUS_EQUALS", r"-="),
+    ("MULTIPLY_EQUALS", r"\*="),
+    ("DIVIDE_EQUALS", r"/="),
+    ("ASSIGN_MOD", r"%="),
+    ("ASSIGN_SHIFT_LEFT", r"<<="),
+    ("ASSIGN_SHIFT_RIGHT", r">>="),
+    ("BITWISE_SHIFT_LEFT", r"<<"),
+    ("BITWISE_SHIFT_RIGHT", r">>"),
+    ("EQUALS", r"="),
+    ("PLUS", r"\+"),
+    ("MINUS", r"-"),
+    ("MULTIPLY", r"\*"),
+    ("DIVIDE", r"/"),
+    ("MODULUS", r"%"),
+    ("LESS_EQUAL", r"<="),
+    ("GREATER_EQUAL", r">="),
+    ("NOT_EQUAL", r"!="),
+    ("LESS_THAN", r"<"),
+    ("GREATER_THAN", r">"),
+    ("AND", r"&&"),
+    ("OR", r"\|\|"),
+    ("BINARY_AND", r"&"),
+    ("BINARY_OR", r"\|"),
+    ("BINARY_XOR", r"\^"),
+    ("BINARY_NOT", r"~"),
+    ("QUESTION", r"\?"),
+    ("COLON", r":"),
+]
+
+KEYWORDS = {
+    "struct": "STRUCT",
+    "layout": "LAYOUT",
+    "uniform": "UNIFORM",
+    "sampler2D": "SAMPLER2D",
+    "samplerCube": "SAMPLERCUBE",
+    "vec2": "VEC2",
+    "vec3": "VEC3",
+    "vec4": "VEC4",
+    "ivec2": "IVEC2",
+    "ivec3": "IVEC3",
+    "ivec4": "IVEC4",
+    "uvec2": "UVEC2",
+    "uvec3": "UVEC3",
+    "uvec4": "UVEC4",
+    "bvec2": "BVEC2",
+    "bvec3": "BVEC3",
+    "bvec4": "BVEC4",
+    "int": "INT",
+    "uint": "UINT",
+    "bool": "BOOL",
+    "float": "FLOAT",
+    "double": "DOUBLE",
+    "void": "VOID",
+    "return": "RETURN",
+    "if": "IF",
+    "else": "ELSE",
+    "for": "FOR",
+    "while": "WHILE",
+    "do": "DO",
+    "switch": "SWITCH",
+    "case": "CASE",
+    "default": "DEFAULT",
+    "break": "BREAK",
+    "continue": "CONTINUE",
+    "discard": "DISCARD",
+    "in": "IN",
+    "out": "OUT",
+    "inout": "INOUT",
+    "attribute": "ATTRIBUTE",
+    "varying": "VARYING",
+    "const": "CONST",
+    "precision": "PRECISION",
+    "highp": "HIGHP",
+    "mediump": "MEDIUMP",
+    "lowp": "LOWP",
+    "subpassInput": "SUBPASSINPUT",
+    "subpassInputMS": "SUBPASSINPUTMS",
+    "sampler2DArray": "SAMPLER2DARRAY",
+    "sampler2DMS": "SAMPLER2DMS",
+    "sampler2DMSArray": "SAMPLER2DMSARRAY",
+    "sampler3D": "SAMPLER3D",
+    "samplerCubeArray": "SAMPLERCUBEARRAY",
+    "image2D": "IMAGE2D",
+    "image3D": "IMAGE3D",
+    "imageCube": "IMAGECUBE",
+    "imageBuffer": "IMAGEBUFFER",
+    "image2DArray": "IMAGE2DARRAY",
+    "imageCubeArray": "IMAGECUBEARRAY",
+    "image1D": "IMAGE1D",
+    "image1DArray": "IMAGE1DARRAY",
+    "image2DMS": "IMAGE2DMS",
+    "image2DMSArray": "IMAGE2DMSARRAY",
+    "atomic_uint": "ATOMICUINT",
+    "mat2": "MAT2",
+    "mat3": "MAT3",
+    "mat4": "MAT4",
+}
+
+VALID_DATA_TYPES = [
+    "int",
+    "float",
+    "double",
+    "vec2",
+    "vec3",
+    "vec4",
+    "mat2",
+    "mat3",
+    "mat4",
+    "uint",
+    "bool",
+    "void",
+]
+
+
+class VulkanLexer:
+    def __init__(self, code):
+        self.code = code
+        self.tokens = []
+        self.tokenize()
+
+    def tokenize(self):
+        pos = 0
+        while pos < len(self.code):
+            match = None
+            for token_type, pattern in TOKENS:
+                regex = re.compile(pattern)
+                match = regex.match(self.code, pos)
+                if match:
+                    text = match.group(0)
+                    if token_type == "IDENTIFIER" and text in KEYWORDS:
+                        token_type = KEYWORDS[text]
+                    if token_type == "VERSION":
+                        self.tokens.append((token_type, text))
+                    elif token_type == "VERSION_NUMBER":
+                        self.tokens.append((token_type, text))
+                    elif token_type == "CORE":
+                        self.tokens.append((token_type, text))
+                    elif token_type != "WHITESPACE":  # Ignore whitespace tokens
+                        token = (token_type, text)
+                        self.tokens.append(token)
+                    pos = match.end(0)
+                    break
+            if not match:
+                unmatched_char = self.code[pos]
+                highlighted_code = (
+                    self.code[:pos] + "[" + self.code[pos] + "]" + self.code[pos + 1 :]
+                )
+                raise SyntaxError(
+                    f"Illegal character '{unmatched_char}' at position {pos}\n{highlighted_code}"
+                )
+
+        self.tokens.append(("EOF", None))
diff --git a/crosstl/src/backend/Vulkan/VulkanParser.py b/crosstl/src/backend/Vulkan/VulkanParser.py
new file mode 100644
index 00000000..6e88f608
--- /dev/null
+++ b/crosstl/src/backend/Vulkan/VulkanParser.py
@@ -0,0 +1,665 @@
+from VulkanLexer import *
+from VulkanAst import *
+
+
+class VulkanParser:
+    def __init__(self, tokens):
+        self.tokens = tokens
+        self.pos = 0
+        self.current_token = self.tokens[self.pos]
+        self.skip_comments()
+
+    def skip_comments(self):
+        while self.current_token[0] in ["COMMENT_SINGLE", "COMMENT_MULTI"]:
+            self.eat(self.current_token[0])
+
+    def peek(self, offset):
+        """Look ahead by offset tokens without consuming them."""
+        peek_index = self.pos + offset
+        if peek_index < len(self.tokens):
+            return self.tokens[peek_index][
+                0
+            ]  # Return the type of the token at the peeked index
+        return None
+
+    def eat(self, token_type):
+        if self.current_token[0] == token_type:
+            self.pos += 1
+            self.current_token = (
+                self.tokens[self.pos] if self.pos < len(self.tokens) else ("EOF", None)
+            )
+            self.skip_comments()
+        else:
+            raise SyntaxError(f"Expected {token_type}, got {self.current_token[0]}")
+
+    def parse(self):
+        module = self.parse_module()
+        self.eat("EOF")
+        return module
+
+    def parse_module(self):
+        statements = []
+        while self.current_token[0] != "EOF":
+            if self.current_token[0] == "LAYOUT":
+                statements.append(self.parse_layout())
+            elif self.current_token[0] == "STRUCT":
+                statements.append(self.parse_struct())
+            elif self.current_token[0] == "UNIFORM":
+                statements.append(self.parse_uniform())
+            elif (
+                self.current_token[1] in VALID_DATA_TYPES
+                and self.peek(1) == "IDENTIFIER"
+                and self.peek(2) == "LPAREN"
+            ):
+                statements.append(self.parse_function())
+            elif (
+                self.current_token[0] == "IDENTIFIER"
+                or self.current_token[1] in VALID_DATA_TYPES
+            ):
+                statements.append(self.parse_variable())
+            else:
+                self.eat(self.current_token[0])
+        return ShaderNode(None, None, None, statements)
+
+    def parse_layout(self):
+        self.eat("LAYOUT")
+        self.eat("LPAREN")
+        bindings = []  # Stores pairs like ('location', '0'), ('binding', '1'), etc.
+        push_constant = False
+        if self.current_token[0] == "PUSH_CONSTANT":
+            push_constant = True
+            self.eat("PUSH_CONSTANT")
+        if self.current_token[0] == "COMMA":
+            self.eat("COMMA")
+
+        # Parse layout bindings
+        while self.current_token[0] != "RPAREN":
+            binding_name = self.current_token[1]
+            self.eat("IDENTIFIER")
+
+            # Handle assignment with EQUALS and a number
+            if self.current_token[0] == "EQUALS":
+                self.eat("EQUALS")
+                binding_value = self.current_token[1]
+                self.eat("NUMBER")
+                bindings.append((binding_name, binding_value))
+            else:
+                bindings.append((binding_name, None))
+
+            if self.current_token[0] == "COMMA":
+                self.eat("COMMA")
+
+        self.eat("RPAREN")
+
+        layout_type = None
+        if self.current_token[0] in ["IN", "OUT", "UNIFORM", "BUFFER"]:
+            layout_type = self.current_token[0]
+            self.eat(layout_type)
+            if self.current_token[0] == "IDENTIFIER":
+                self.eat(self.current_token[0])
+
+        data_type = None
+        struct_fields = None
+        if layout_type in ["UNIFORM", "BUFFER"]:
+            # If a curly brace follows, we have a structured data block
+            if self.current_token[0] == "LBRACE":
+                self.eat("LBRACE")
+                struct_fields = []
+
+                # Parse structured fields within the uniform/push_constant/buffer block
+                while self.current_token[0] != "RBRACE":
+                    if self.current_token[1] in VALID_DATA_TYPES:
+                        field_type = self.current_token[1]  # Field type (e.g., mat4)
+                        self.eat(self.current_token[0])
+                    else:
+                        raise SyntaxError(
+                            "Expected some data type before an identifier"
+                        )
+                    field_name = self.current_token[1]  # Field name
+                    self.eat("IDENTIFIER")
+                    self.eat("SEMICOLON")
+                    struct_fields.append((field_type, field_name))
+
+                self.eat("RBRACE")
+                data_type = "struct"  # Use 'struct' as data_type placeholder for uniform/push_constant/buffer
+            else:
+                raise SyntaxError(
+                    "Expected structured data block after 'uniform' or 'buffer'"
+                )
+        else:
+            # For `in` and `out`, expect a data type and variable name
+            if self.current_token[1] in VALID_DATA_TYPES:
+                data_type = self.current_token[1]
+                self.eat(self.current_token[0])
+            else:
+                raise SyntaxError(f"Unexpected type: {self.current_token[1]}")
+
+        # Parse variable name
+        variable_name = None
+        if self.current_token[0] == "IDENTIFIER":
+            variable_name = self.current_token[1]
+            self.eat("IDENTIFIER")
+
+        self.eat("SEMICOLON")
+        return LayoutNode(
+            bindings,
+            push_constant,
+            layout_type,
+            data_type,
+            variable_name,
+            struct_fields,
+        )
+
+    def parse_push_constant(self):
+        self.eat("PUSH_CONSTANT")
+        self.eat("LBRACE")
+        members = []
+        while self.current_token[0] != "RBRACE":
+            members.append(self.parse_variable())
+        self.eat("RBRACE")
+        return PushConstantNode(members)
+
+    def parse_descriptor_set(self):
+        self.eat("DESCRIPTOR_SET")
+        set_number = self.current_token[1]
+        self.eat("NUMBER")
+        self.eat("LBRACE")
+        bindings = []
+        while self.current_token[0] != "RBRACE":
+            bindings.append(self.parse_variable())
+        self.eat("RBRACE")
+        return DescriptorSetNode(set_number, bindings)
+
+    def parse_struct(self):
+        self.eat("STRUCT")
+        name = self.current_token[1]
+        self.eat("IDENTIFIER")
+        self.eat("LBRACE")
+        members = []
+        type_name = None
+        while self.current_token[0] != "RBRACE":
+            if self.current_token[1] in VALID_DATA_TYPES:
+                type_name = self.current_token[1]
+                self.eat(self.current_token[0])
+            if self.current_token[0] == "IDENTIFIER":
+                members.append(self.parse_variable(type_name))
+        self.eat("RBRACE")
+        return StructNode(name, members)
+
+    def parse_function(self):
+        return_type = self.current_token[1]
+        if self.current_token[1] in VALID_DATA_TYPES:
+            self.eat(self.current_token[0])
+        else:
+            raise SyntaxError(f"Unexpected type: {self.current_token[1]}")
+        func_name = self.current_token[1]
+        self.eat("IDENTIFIER")
+        self.eat("LPAREN")
+        params = self.parse_parameters()
+        self.eat("RPAREN")
+        body = self.parse_block()
+        return FunctionNode(func_name, return_type, params, body)
+
+    def parse_parameters(self):
+        params = []
+        while self.current_token[0] != "RPAREN":
+            vtype = self.current_token[1]
+            self.eat(self.current_token[0])
+            name = self.current_token[1]
+            self.eat("IDENTIFIER")
+            params.append(VariableNode(vtype, name))
+            if self.current_token[0] == "COMMA":
+                self.eat("COMMA")
+        return params
+
+    def parse_block(self):
+        self.eat("LBRACE")
+        statements = []
+        while self.current_token[0] != "RBRACE":
+            statements.append(self.parse_body())
+        self.eat("RBRACE")
+        return statements
+
+    def parse_body(self):
+        token_type = self.current_token[0]
+
+        if token_type == "IDENTIFIER" or self.current_token[1] in VALID_DATA_TYPES:
+            return self.parse_assignment_or_function_call()
+        elif token_type == "IF":
+            return self.parse_if_statement()
+        elif token_type == "FOR":
+            return self.parse_for_statement()
+        elif token_type == "WHILE":
+            return self.parse_while_statement()
+        elif token_type == "DO":
+            return self.parse_do_while_statement()
+        elif token_type == "SWITCH":
+            return self.parse_switch_statement()
+        elif token_type == "BREAK":
+            self.eat("BREAK")
+            self.eat("SEMICOLON")
+            return BreakNode()
+        else:
+            return self.parse_expression_statement()
+
+    def parse_update(self):
+        if self.current_token[0] == "IDENTIFIER":
+            name = self.current_token[1]
+            self.eat("IDENTIFIER")
+            if self.current_token[0] == "POST_INCREMENT":
+                self.eat("POST_INCREMENT")
+                return UnaryOpNode("POST_INCREMENT", VariableNode(name, ""))
+            elif self.current_token[0] == "POST_DECREMENT":
+                self.eat("POST_DECREMENT")
+                return UnaryOpNode("POST_DECREMENT", VariableNode(name, ""))
+            elif self.current_token[0] in [
+                "EQUALS",
+                "ASSIGN_ADD",
+                "ASSIGN_SUB",
+                "ASSIGN_MUL",
+                "ASSIGN_DIV",
+            ]:
+                op = self.current_token[0]
+                self.eat(op)
+                value = self.parse_expression()
+                if op == "EQUALS":
+                    return AssignmentNode(name, value)
+                elif op == "ASSIGN_ADD":
+                    return AssignmentNode(
+                        name, BinaryOpNode(VariableNode(name, ""), "+", value)
+                    )
+                elif op == "ASSIGN_SUB":
+                    return AssignmentNode(
+                        name, BinaryOpNode(VariableNode(name, ""), "-", value)
+                    )
+                elif op == "ASSIGN_MUL":
+                    return AssignmentNode(
+                        name, BinaryOpNode(VariableNode(name, ""), "*", value)
+                    )
+                elif op == "ASSIGN_DIV":
+                    return AssignmentNode(
+                        name, BinaryOpNode(VariableNode(name, ""), "/", value)
+                    )
+                else:
+                    raise SyntaxError(
+                        f"Expected INCREMENT or DECREMENT, got {self.current_token[0]}"
+                    )
+        elif self.current_token[0] == "PRE_INCREMENT":
+            self.eat("PRE_INCREMENT")
+            if self.current_token[0] == "IDENTIFIER":
+                name = self.current_token[1]
+                self.eat("IDENTIFIER")
+                return UnaryOpNode("PRE_INCREMENT", VariableNode(name, ""))
+            else:
+                raise SyntaxError(
+                    f"Expected IDENTIFIER after PRE_INCREMENT, got {self.current_token[0]}"
+                )
+        elif self.current_token[0] == "PRE_DECREMENT":
+            self.eat("PRE_DECREMENT")
+            if self.current_token[0] == "IDENTIFIER":
+                name = self.current_token[1]
+                self.eat("IDENTIFIER")
+                return UnaryOpNode("PRE_DECREMENT", VariableNode(name, ""))
+            else:
+                raise SyntaxError(
+                    f"Expected IDENTIFIER after PRE_DECREMENT, got {self.current_token[0]}"
+                )
+        else:
+            raise SyntaxError(f"Unexpected token in update: {self.current_token[0]}")
+
+    def parse_if_statement(self):
+        self.eat("IF")
+        self.eat("LPAREN")
+        if_condition = self.parse_expression()
+        self.eat("RPAREN")
+        if_body = self.parse_block()
+        else_body = None
+        else_if_condition = []
+        else_if_body = []
+        while self.current_token[0] == "ELSE" and self.peek(1) == "IF":
+            self.eat("ELSE")
+            self.eat("IF")
+            self.eat("LPAREN")
+            else_if_condition.append(self.parse_expression())
+            self.eat("RPAREN")
+            self.eat("LBRACE")
+            else_if_body.append(self.parse_body())
+            self.eat("RBRACE")
+        if self.current_token[0] == "ELSE":
+            self.eat("ELSE")
+            else_body = self.parse_block()
+        return IfNode(if_condition, if_body, else_if_condition, else_if_body, else_body)
+
+    def parse_for_statement(self):
+        self.eat("FOR")
+        self.eat("LPAREN")
+        initialization = self.parse_assignment_or_function_call()
+        condition = self.parse_expression()
+        self.eat("SEMICOLON")
+        increment = self.parse_update()
+        self.eat("RPAREN")
+        body = self.parse_block()
+        return ForNode(initialization, condition, increment, body)
+
+    def parse_variable(self, type_name):
+        name = self.current_token[1]
+        self.eat("IDENTIFIER")
+
+        while self.current_token[0] == "DOT":
+            self.eat("DOT")
+            member_name = self.current_token[1]
+            self.eat("IDENTIFIER")
+            name += "." + member_name
+
+        if self.current_token[0] == "SEMICOLON":
+            self.eat("SEMICOLON")
+            return VariableNode(name, type_name)
+
+        elif self.current_token[0] == "EQUALS":
+            self.eat("EQUALS")
+            value = self.parse_expression()
+
+            if self.current_token[0] == "SEMICOLON":
+                self.eat("SEMICOLON")
+                return AssignmentNode(VariableNode(name, type_name), value)
+            else:
+                raise SyntaxError(
+                    f"Expected ';' after variable assignment, found: {self.current_token[0]}"
+                )
+
+        elif self.current_token[0] in (
+            "EQUALS",
+            "PLUS_EQUALS",
+            "MINUS_EQUALS",
+            "MULTIPLY_EQUALS",
+            "DIVIDE_EQUALS",
+            "EQUAL",
+            "LESS_THAN",
+            "GREATER_THAN",
+            "LESS_EQUAL",
+            "GREATER_EQUAL",
+            "ASSIGN_AND",
+            "ASSIGN_OR",
+            "ASSIGN_XOR",
+            "ASSIGN_MOD",
+            "BITWISE_SHIFT_RIGHT",
+            "BITWISE_SHIFT_LEFT",
+            "BITWISE_XOR",
+            "ASSIGN_SHIFT_LEFT",
+            "ASSIGN_SHIFT_RIGHT",
+        ):
+            op = self.current_token[0]
+            op_name = self.current_token[1]
+            self.eat(op)
+            value = self.parse_expression()
+            if self.current_token[0] == "SEMICOLON":
+                self.eat("SEMICOLON")
+                return BinaryOpNode(VariableNode(name, type_name), op_name, value)
+            else:
+                raise SyntaxError(
+                    f"Expected ';' after compound assignment, found: {self.current_token[0]}"
+                )
+        else:
+            raise SyntaxError(
+                f"Unexpected token in variable declaration: {self.current_token[0]}"
+            )
+
+    def parse_member_access(self, object):
+        self.eat("DOT")
+        if self.current_token[0] != "IDENTIFIER":
+            raise SyntaxError(
+                f"Expected identifier after dot, got {self.current_token[0]}"
+            )
+        member = self.current_token[1]
+        self.eat("IDENTIFIER")
+
+        if self.current_token[0] == "DOT":
+            return self.parse_member_access(MemberAccessNode(object, member))
+
+        return MemberAccessNode(object, member)
+
+    def parse_function_call(self, name):
+        self.eat("LPAREN")
+        args = []
+        if self.current_token[0] != "RPAREN":
+            args.append(self.parse_expression())
+            while self.current_token[0] == "COMMA":
+                self.eat("COMMA")
+                args.append(self.parse_expression())
+        self.eat("RPAREN")
+        return FunctionCallNode(name, args)
+
+    def parse_function_call_or_identifier(self):
+        func_name = self.current_token[1]
+        self.eat(self.current_token[0])
+
+        if self.current_token[0] == "LPAREN":
+            return self.parse_function_call(func_name)
+        elif self.current_token[0] == "DOT":
+            return self.parse_member_access(func_name)
+        return VariableNode(func_name, "")
+
+    def parse_primary(self):
+        if self.current_token[0] == "MINUS":
+            self.eat("MINUS")
+            value = self.parse_primary()
+            return UnaryOpNode("-", value)
+
+        if (
+            self.current_token[0] == "IDENTIFIER"
+            or self.current_token[1] in VALID_DATA_TYPES
+        ):
+            return self.parse_function_call_or_identifier()
+        elif self.current_token[0] == "NUMBER":
+            value = self.current_token[1]
+            self.eat("NUMBER")
+            return value
+        elif self.current_token[0] == "LPAREN":
+            self.eat("LPAREN")
+            expr = self.parse_expression()
+            self.eat("RPAREN")
+            return expr
+        else:
+            raise SyntaxError(
+                f"Unexpected token in expression: {self.current_token[0]}"
+            )
+
+    def parse_multiplicative(self):
+        left = self.parse_primary()
+        while self.current_token[0] in ["MULTIPLY", "DIVIDE"]:
+            op = self.current_token[0]
+            self.eat(op)
+            right = self.parse_primary()
+            left = BinaryOpNode(left, op, right)
+        return left
+
+    def parse_additive(self):
+        left = self.parse_multiplicative()
+        while self.current_token[0] in ["PLUS", "MINUS"]:
+            op = self.current_token[0]
+            self.eat(op)
+            right = self.parse_multiplicative()
+            left = BinaryOpNode(left, op, right)
+        return left
+
+    def parse_assignment(self, name):
+        if self.current_token[0] in [
+            "EQUALS",
+            "PLUS_EQUALS",
+            "MINUS_EQUALS",
+            "MULTIPLY_EQUALS",
+            "DIVIDE_EQUALS",
+            "LESS_THAN",
+            "GREATER_THAN",
+            "LESS_EQUAL",
+            "GREATER_EQUAL",
+            "ASSIGN_AND",
+            "ASSIGN_OR",
+            "ASSIGN_XOR",
+            "ASSIGN_MOD",
+            "BITWISE_SHIFT_RIGHT",
+            "BITWISE_SHIFT_LEFT",
+            "BITWISE_XOR",
+            "ASSIGN_SHIFT_LEFT",
+            "ASSIGN_SHIFT_RIGHT",
+        ]:
+            op = self.current_token[0]
+            op_name = self.current_token[1]
+            self.eat(op)
+            value = self.parse_expression()
+            if self.current_token[0] == "SEMICOLON":
+                self.eat("SEMICOLON")
+            return BinaryOpNode(name, op_name, value)
+        else:
+            raise SyntaxError(
+                f"Expected assignment operator, found: {self.current_token[0]}"
+            )
+
+    def parse_assignment_or_function_call(self):
+        type_name = ""
+        if self.current_token[0] == "IDENTIFIER" and self.peek(1) in [
+            "POST_INCREMENT",
+            "POST_DECREMENT",
+        ]:
+            name = self.current_token[1]
+            self.eat("IDENTIFIER")
+
+            if self.current_token[0] in [
+                "EQUALS",
+                "PLUS_EQUALS",
+                "MINUS_EQUALS",
+                "MULTIPLY_EQUALS",
+                "DIVIDE_EQUALS",
+                "LESS_THAN",
+                "GREATER_THAN",
+                "LESS_EQUAL",
+                "GREATER_EQUAL",
+                "ASSIGN_AND",
+                "ASSIGN_OR",
+                "ASSIGN_XOR",
+                "ASSIGN_MOD",
+                "BITWISE_SHIFT_RIGHT",
+                "BITWISE_SHIFT_LEFT",
+                "BITWISE_XOR",
+                "ASSIGN_SHIFT_LEFT",
+                "ASSIGN_SHIFT_RIGHT",
+            ]:
+                return self.parse_assignment(name)  # todo
+            elif self.current_token[0] == "POST_INCREMENT":
+                self.eat("POST_INCREMENT")
+                self.eat("SEMICOLON")
+                return AssignmentNode(
+                    name, UnaryOpNode("POST_INCREMENT", VariableNode("", name))
+                )
+            elif self.current_token[0] == "POST_DECREMENT":
+                self.eat("POST_DECREMENT")
+                self.eat("SEMICOLON")
+                return AssignmentNode(
+                    name, UnaryOpNode("POST_DECREMENT", VariableNode("", name))
+                )
+            elif self.current_token[0] == "LPAREN":
+                return self.parse_function_call(name)
+            else:
+                raise SyntaxError(
+                    f"Unexpected token after identifier: {self.current_token[0]}"
+                )
+        if self.current_token[1] in VALID_DATA_TYPES:
+            type_name = self.current_token[1]
+            self.eat(self.current_token[0])
+        if self.current_token[0] == "IDENTIFIER":
+            return self.parse_variable(type_name)
+
+    def parse_expression(self):
+        left = self.parse_additive()
+        while self.current_token[0] in [
+            "LESS_THAN",
+            "GREATER_THAN",
+            "LESS_EQUAL",
+            "GREATER_EQUAL",
+            "EQUAL",
+            "NOT_EQUAL",
+            "AND",
+            "OR",
+        ]:
+            op = self.current_token[0]
+            self.eat(op)
+            right = self.parse_additive()
+            left = BinaryOpNode(left, op, right)
+
+        if self.current_token[0] == "QUESTION":
+            self.eat("QUESTION")
+            true_expr = self.parse_expression()
+            self.eat("COLON")
+            false_expr = self.parse_expression()
+            left = TernaryOpNode(left, true_expr, false_expr)
+
+        return left
+
+    def parse_expression_statement(self):
+        expr = self.parse_expression()
+        # self.eat("SEMICOLON")
+        return expr
+
+    def parse_while_statement(self):
+        self.eat("WHILE")
+        self.eat("LPAREN")
+        condition = self.parse_expression()
+        self.eat("RPAREN")
+        body = self.parse_block()
+        return WhileNode(condition, body)
+
+    def parse_do_while_statement(self):
+        self.eat("DO")
+        body = self.parse_block()
+        self.eat("WHILE")
+        self.eat("LPAREN")
+        condition = self.parse_expression()
+        self.eat("RPAREN")
+        self.eat("SEMICOLON")
+        return DoWhileNode(condition, body)
+
+    def parse_switch_statement(self):
+        self.eat("SWITCH")
+        self.eat("LPAREN")
+        expr = self.parse_expression()
+        self.eat("RPAREN")
+        self.eat("LBRACE")
+        cases = []
+        while self.current_token[0] != "RBRACE":
+            cases.append(self.parse_case_statement())
+        self.eat("RBRACE")
+        return SwitchNode(expr, cases)
+
+    def parse_case_statement(self):
+        if self.current_token[0] == "CASE":
+            self.eat("CASE")
+            value = self.parse_expression()
+            self.eat("COLON")
+        elif self.current_token[0] == "DEFAULT":
+            self.eat("DEFAULT")
+            value = None
+            self.eat("COLON")
+        statements = []
+        while self.current_token[0] not in ["CASE", "DEFAULT", "RBRACE"]:
+            statements.append(self.parse_body())
+        return CaseNode(value, statements)
+
+    def parse_default_statement(self):
+        self.eat("DEFAULT")
+        self.eat("COLON")
+        statements = []
+        while self.current_token[0] not in ["CASE", "RBRACE"]:
+            statements.append(self.parse_body())
+        return DefaultNode(statements)
+
+    def parse_uniform(self):
+        self.eat("UNIFORM")
+        var_type = self.current_token[1]
+        if self.current_token[1] in VALID_DATA_TYPES:
+            self.eat(self.current_token[0])
+        else:
+            raise SyntaxError(f"Unexpected type: {self.current_token[1]}")
+        name = self.current_token[1]
+        self.eat("IDENTIFIER")
+        self.eat("SEMICOLON")
+        return UniformNode(name, var_type)
diff --git a/crosstl/src/translator/codegen/directx_codegen.py b/crosstl/src/translator/codegen/directx_codegen.py
index c013e404..7f390a29 100644
--- a/crosstl/src/translator/codegen/directx_codegen.py
+++ b/crosstl/src/translator/codegen/directx_codegen.py
@@ -258,6 +258,7 @@ def map_operator(self, op):
             "MULTIPLY": "*",
             "DIVIDE": "/",
             "BITWISE_XOR": "^",
+            "BITWISE_AND": "&",
             "LESS_THAN": "<",
             "GREATER_THAN": ">",
             "ASSIGN_ADD": "+=",
@@ -277,6 +278,8 @@ def map_operator(self, op):
             "ASSIGN_AND": "&=",
             "LOGICAL_AND": "&&",
             "ASSIGN_XOR": "^=",
+            "shift_left": "<<",
+            "shift_right": ">>",
         }
         return op_map.get(op, op)
 
diff --git a/crosstl/src/translator/codegen/metal_codegen.py b/crosstl/src/translator/codegen/metal_codegen.py
index 50cc592e..11b59495 100644
--- a/crosstl/src/translator/codegen/metal_codegen.py
+++ b/crosstl/src/translator/codegen/metal_codegen.py
@@ -343,6 +343,7 @@ def map_operator(self, op):
             "MULTIPLY": "*",
             "DIVIDE": "/",
             "BITWISE_XOR": "^",
+            "BITWISE_AND": "&",
             "LESS_THAN": "<",
             "GREATER_THAN": ">",
             "ASSIGN_ADD": "+=",
diff --git a/crosstl/src/translator/codegen/slang_codegen.py b/crosstl/src/translator/codegen/slang_codegen.py
new file mode 100644
index 00000000..1f462437
--- /dev/null
+++ b/crosstl/src/translator/codegen/slang_codegen.py
@@ -0,0 +1,22 @@
+from ..ast import (
+    AssignmentNode,
+    BinaryOpNode,
+    ForNode,
+    FunctionCallNode,
+    IfNode,
+    MemberAccessNode,
+    ReturnNode,
+    StructNode,
+    TernaryOpNode,
+    UnaryOpNode,
+    VariableNode,
+)
+
+
+# ToDO: Implement the SlangCodeGen class
+class SlangCodeGen:
+    def __init__(self):
+        pass
+
+    def generate(self, ast):
+        pass
diff --git a/crosstl/src/translator/lexer.py b/crosstl/src/translator/lexer.py
index a4faa411..e6540499 100644
--- a/crosstl/src/translator/lexer.py
+++ b/crosstl/src/translator/lexer.py
@@ -73,6 +73,8 @@
     ("BITWISE_OR", r"\|"),
     ("BITWISE_XOR", r"\^"),
     ("BITWISE_NOT", r"~"),
+    ("shift_left", r"<<"),
+    ("shift_right", r">>"),
 ]
 
 KEYWORDS = {
diff --git a/crosstl/src/translator/parser.py b/crosstl/src/translator/parser.py
index 4e4fb1c4..eeca778c 100644
--- a/crosstl/src/translator/parser.py
+++ b/crosstl/src/translator/parser.py
@@ -439,8 +439,11 @@ def parse_assignment_or_function_call(self, update_condition=False):
             "BITWISE_SHIFT_RIGHT",
             "BITWISE_SHIFT_LEFT",
             "BITWISE_XOR",
+            "BITWISE_AND",
             "ASSIGN_SHIFT_LEFT",
             "ASSIGN_SHIFT_RIGHT",
+            "SHIFT_LEFT",
+            "SHIFT_RIGHT",
         ]:
             return self.parse_assignment(name)
         elif self.current_token[0] == "INCREMENT":
@@ -507,6 +510,7 @@ def parse_variable_declaration(self, type_name, update_condition=False):
             "BITWISE_SHIFT_RIGHT",
             "BITWISE_SHIFT_LEFT",
             "BITWISE_XOR",
+            "BITWISE_AND",
             "ASSIGN_SHIFT_LEFT" "ASSIGN_SHIFT_RIGHT",
         ]:
             op = self.current_token[1]
@@ -538,6 +542,7 @@ def parse_variable_declaration(self, type_name, update_condition=False):
             "BITWISE_SHIFT_RIGHT",
             "BITWISE_SHIFT_LEFT",
             "BITWISE_XOR",
+            "BITWISE_AND",
             "EQUAL",
             "ASSIGN_AND",
             "ASSIGN_OR",
@@ -599,6 +604,7 @@ def parse_assignment(self, name):
             "BITWISE_SHIFT_RIGHT",
             "BITWISE_SHIFT_LEFT",
             "BITWISE_XOR",
+            "BITWISE_AND",
             "ASSIGN_SHIFT_RIGHT",
             "ASSIGN_SHIFT_LEFT",
         ]:
@@ -790,6 +796,7 @@ def parse_expression(self):
             "BITWISE_SHIFT_RIGHT",
             "BITWISE_SHIFT_LEFT",
             "BITWISE_XOR",
+            "BITWISE_AND",
             "ASSIGN_SHIFT_RIGHT",
             "ASSIGN_SHIFT_LEFT",
         ]:
diff --git a/getting_start.ipynb b/getting_start.ipynb
index c0d7d4d0..66a0fa8a 100644
--- a/getting_start.ipynb
+++ b/getting_start.ipynb
@@ -32,14 +32,14 @@
     "📚 **Documentation**\n",
     "Comprehensive documentation is available to help you get started and master CrossGL:\n",
     "\n",
-    "🔗 [CrossGL Documentation](https://crossgl.github.io/language.html)\n",
-    "📘 [Contribution Guidelines](https://crossgl.github.io/contribution.html)\n",
+    "🔗 [CrossGL Documentation](https://crossgl.github.io/crossgl-docs/language.html)\n",
+    "📘 [Contribution Guidelines](https://crossgl.github.io/crossgl-docs/contribution.html)\n",
     "\n",
     "\n",
     "🤝 **Community & Social Media**\n",
     "Join our vibrant community of developers and graphics enthusiasts:\n",
     "\n",
-    "💬 [Discord Channel](https://discord.gg/mYH45zZ9)\n",
+    "💬 [Discord Channel](https://discord.com/invite/uyRQKXhcyW)\n",
     "- Get real-time support\n",
     "- Share your projects\n",
     "- Collaborate with other CrossGL users\n",


Test patch:
diff --git a/tests/test_backend/test_directx/test_codegen.py b/tests/test_backend/test_directx/test_codegen.py
index a7ca79d6..07ae81b6 100644
--- a/tests/test_backend/test_directx/test_codegen.py
+++ b/tests/test_backend/test_directx/test_codegen.py
@@ -160,6 +160,101 @@ def test_for_codegen():
         pytest.fail("For loop parsing or code generation not implemented.")
 
 
+def test_while_codegen():
+    code = """
+    struct VSInput {
+    float4 position : POSITION;
+    float4 color : TEXCOORD0;
+    };
+
+    struct VSOutput {
+        float4 out_position : TEXCOORD0;
+    };
+
+    VSOutput VSMain(VSInput input) {
+        VSOutput output;
+        output.out_position = input.position;
+        int i = 0;
+        while (i < 10) {
+            output.out_position = input.color;
+            i = i + 1;  // Increment the loop variable
+        }
+        return output;
+    }
+
+    struct PSInput {
+        float4 in_position : TEXCOORD0;
+    };
+
+    struct PSOutput {
+        float4 out_color : SV_TARGET0;
+    };
+
+    PSOutput PSMain(PSInput input) {
+        PSOutput output;
+        output.out_color = input.in_position;
+        int i = 0;
+        while (i < 10) {
+            output.out_color = float4(1.0, 1.0, 1.0, 1.0);
+            i = i + 1;  // Increment the loop variable
+        }
+        return output;
+    }
+    """
+    try:
+        tokens = tokenize_code(code)
+        ast = parse_code(tokens)
+        generated_code = generate_code(ast)
+        print(generated_code)
+    except SyntaxError:
+        pytest.fail("While loop parsing or code generation not implemented.")
+
+
+def test_do_while_codegen():
+    code = """
+    struct VSInput {
+        float4 position : POSITION;
+        float4 color : TEXCOORD0;
+    };
+    struct VSOutput {
+        float4 out_position : TEXCOORD0;
+    };
+    VSOutput VSMain(VSInput input) {
+        VSOutput output;
+        output.out_position = input.position;
+        int i = 0;
+        do {
+            output.out_position = input.color;
+            i = i + 1;  // Increment the loop variable
+        } while (i < 10);
+        return output;
+    }
+    struct PSInput {
+        float4 in_position : TEXCOORD0;
+    };
+    struct PSOutput {
+        float4 out_color : SV_TARGET0;
+    };
+    PSOutput PSMain(PSInput input) {
+        PSOutput output;
+        output.out_color = input.in_position;
+        int i = 0;
+        do {
+            output.out_color = float4(1.0, 1.0, 1.0, 1.0);
+            i = i + 1;  // Increment the loop variable
+        } while (i < 10);
+        return output;
+    }
+    """
+    try:
+        tokens = tokenize_code(code)
+        ast = parse_code(tokens)
+        generated_code = generate_code(ast)
+        print(generated_code)
+    except SyntaxError:
+        pytest.fail("While loop parsing or code generation not implemented.")
+
+
 def test_else_codegen():
     code = """
     struct VSInput {
@@ -309,7 +404,7 @@ def test_else_if_codegen():
         pytest.fail("Else_if statement parsing or code generation not implemented.")
 
 
-def test_assignment_ops_parsing():
+def test_assignment_ops_codegen():
     code = """
     PSOutput PSMain(PSInput input) {
         PSOutput output;
@@ -331,14 +426,40 @@ def test_assignment_ops_parsing():
             out_color /= 2.0;
         }
 
+        // Testing SHIFT_LEFT (<<) operator on some condition
         if (input.in_position.r == 0.5) {
             uint redValue = asuint(output.out_color.r);
             output.redValue ^= 0x1;
             output.out_color.r = asfloat(redValue);
 
-            outpu.redValue |= 0x2;
+            output.redValue |= 0x2;
+            // Applying shift left operation
+            output.redValue << 1; // Shift left by 1
+            output.redValue &= 0x3;
+        }
+        
+        // Testing SHIFT_RIGHT (>>) operator on some condition
+        if (input.in_position.r == 0.25) {
+            uint redValue = asuint(output.out_color.r);
+            output.redValue ^= 0x1;
+            output.out_color.r = asfloat(redValue);
+
+            output.redValue |= 0x2;
+            // Applying shift left operation
+            output.redValue >> 1; // Shift left by 1
+            output.redValue &= 0x3;
+        } 
+        
+        // Testing BITWISE_XOR (^) operator on some condition
+        if (input.in_position.r == 0.5) {
+            uint redValue = asuint(output.out_color.r);
+            output.redValue ^ 0x1;  
+            // BITWISE_XOR operation
+            output.out_color.r = asfloat(redValue);
         }
 
+
+
         return output;
     }
     """
@@ -351,5 +472,31 @@ def test_assignment_ops_parsing():
         pytest.fail("assignment ops parsing or code generation not implemented.")
 
 
+def test_bitwise_ops_codgen():
+    code = """
+        PSOutput PSMain(PSInput input) {
+            PSOutput output;
+            output.out_color = float4(0.0, 0.0, 0.0, 1.0);
+            uint val = 0x01;
+            if (val | 0x02) {
+                // Test case for bitwise OR
+            }
+            uint filterA = 0b0001; // First filter
+            uint filterB = 0b1000; // Second filter
+
+            // Merge both filters
+            uint combinedFilter = filterA | filterB; // combinedFilter becomes 0b1001
+            return output;
+        }
+        """
+    try:
+        tokens = tokenize_code(code)
+        ast = parse_code(tokens)
+        generated_code = generate_code(ast)
+        print(generated_code)
+    except SyntaxError:
+        pytest.fail("bitwise_op parsing or codegen not implemented.")
+
+
 if __name__ == "__main__":
     pytest.main()
diff --git a/tests/test_backend/test_directx/test_lexer.py b/tests/test_backend/test_directx/test_lexer.py
index 4cb364d2..cb5ea7fb 100644
--- a/tests/test_backend/test_directx/test_lexer.py
+++ b/tests/test_backend/test_directx/test_lexer.py
@@ -133,12 +133,35 @@ def test_assignment_ops_tokenization():
             output.out_color /= 2.0;
         }
 
+        // Testing SHIFT_LEFT (<<) operator on some condition
         if (input.in_position.r == 0.5) {
             uint redValue = asuint(output.out_color.r);
-            redValue ^= 0x1;
+            output.redValue ^= 0x1;
             output.out_color.r = asfloat(redValue);
+            output.redValue |= 0x2;
+
+            // Applying shift left operation
+            output.redValue << 1; // Shift left by 1
+            redValue |= 0x2;
+
+            redValue &= 0x3;
+        }
+        
+        // Testing SHIFT RIGHT (>>) operator on some condition
+        if (input.in_position.r == 0.25) {
+            uint redValue = asuint(output.out_color.r);
+            output.redValue ^= 0x1;
+            output.out_color.r = asfloat(redValue);
+            output.redValue |= 0x2;
+
+            // Applying shift left operation
+            output.redValue >> 1; // Shift left by 1
+            redValue |= 0x2;
+
+            redValue &= 0x3;
         }
 
+
         return output;
     }
     """
@@ -148,5 +171,16 @@ def test_assignment_ops_tokenization():
         pytest.fail("assign_op tokenization is not implemented.")
 
 
+def test_bitwise_or_tokenization():
+    code = """
+        uint val = 0x01;
+        val = val | 0x02;
+    """
+    try:
+        tokenize_code(code)
+    except SyntaxError:
+        pytest.fail("bitwise_op tokenization is not implemented.")
+
+
 if __name__ == "__main__":
     pytest.main()
diff --git a/tests/test_backend/test_directx/test_parser.py b/tests/test_backend/test_directx/test_parser.py
index eed91e95..809a1825 100644
--- a/tests/test_backend/test_directx/test_parser.py
+++ b/tests/test_backend/test_directx/test_parser.py
@@ -75,6 +75,44 @@ def test_for_parsing():
         pytest.fail("for parsing not implemented.")
 
 
+def test_while_parsing():
+    code = """
+    VSOutput VSMain(VSInput input) {
+        VSOutput output;
+        int i = 0;
+        while (i < 10) {
+            output.out_position = input.position;
+            i = i + 1;
+        }
+        return output;
+    }
+    """
+    try:
+        tokens = tokenize_code(code)
+        parse_code(tokens)
+    except SyntaxError:
+        pytest.fail("while parsing not implemented")
+
+
+def test_do_while_parsing():
+    code = """
+    VSOutput VSMain(VSInput input) {
+        VSOutput output;
+        int i = 0;
+        do {
+            output.out_position = input.position;
+            i = i + 1;
+        } while (i < 10);
+        return output;
+    }
+    """
+    try:
+        tokens = tokenize_code(code)
+        parse_code(tokens)
+    except SyntaxError:
+        pytest.fail("do while parsing not implemented")
+
+
 def test_else_parsing():
     code = """
     PSOutput PSMain(PSInput input) {
@@ -152,14 +190,39 @@ def test_assignment_ops_parsing():
             out_color /= 2.0;
         }
 
+        // Testing SHIFT_LEFT (<<) operator on some condition
         if (input.in_position.r == 0.5) {
             uint redValue = asuint(output.out_color.r);
             output.redValue ^= 0x1;
             output.out_color.r = asfloat(redValue);
 
             output.redValue |= 0x2;
+            // Applying shift left operation
+            output.redValue << 1; // Shift left by 1
+            output.redValue &= 0x3;
+        }
+        
+        // Testing SHIFT_RIGHT (>>) operator on some condition
+        if (input.in_position.r == 0.25) {
+            uint redValue = asuint(output.out_color.r);
+            output.redValue ^= 0x1;
+            output.out_color.r = asfloat(redValue);
+
+            output.redValue |= 0x2;
+            // Applying shift left operation
+            output.redValue >> 1; // Shift left by 1
+            output.redValue &= 0x3;
+        }
+
+        // Testing BITWISE_XOR (^) operator on some condition
+        if (input.in_position.r == 0.5) {
+            uint redValue = asuint(output.out_color.r);
+            output.redValue ^ 0x1;  // BITWISE_XOR operation
+            output.out_color.r = asfloat(redValue);
         }
 
+
+
         return output;
     }
     """
@@ -170,5 +233,29 @@ def test_assignment_ops_parsing():
         pytest.fail("assign_op parsing not implemented.")
 
 
+def test_bitwise_ops_parsing():
+    code = """
+        PSOutput PSMain(PSInput input) {
+            PSOutput output;
+            output.out_color = float4(0.0, 0.0, 0.0, 1.0);
+            uint val = 0x01;
+            if (val | 0x02) {
+                // Test case for bitwise OR
+            }
+            uint filterA = 0b0001; // First filter
+            uint filterB = 0b1000; // Second filter
+
+            // Merge both filters
+            uint combinedFilter = filterA | filterB; // combinedFilter becomes 0b1001
+            return output;
+        }
+        """
+    try:
+        tokens = tokenize_code(code)
+        parse_code(tokens)
+    except SyntaxError:
+        pytest.fail("bitwise_op parsing not implemented.")
+
+
 if __name__ == "__main__":
     pytest.main()
diff --git a/tests/test_translator/test_codegen/test_directx_codegen.py b/tests/test_translator/test_codegen/test_directx_codegen.py
index 686dbf4b..afff181d 100644
--- a/tests/test_translator/test_codegen/test_directx_codegen.py
+++ b/tests/test_translator/test_codegen/test_directx_codegen.py
@@ -559,5 +559,129 @@ def test_bitwise_operators():
         pytest.fail("Bitwise Shift codegen not implemented")
 
 
+def test_bitwise_and_operator():
+    code = """
+    shader main {
+    struct VSInput {
+        vec2 texCoord @ TEXCOORD0;
+    };
+    struct VSOutput {
+        vec4 color @ COLOR;
+    };
+    sampler2D iChannel0;
+    vertex {
+        VSOutput main(VSInput input) {
+            VSOutput output;
+            // Use bitwise AND on texture coordinates (for testing purposes)
+            output.color = vec4(float(int(input.texCoord.x * 100.0) & 15), 
+                                float(int(input.texCoord.y * 100.0) & 15), 
+                                0.0, 1.0);
+            return output;
+        }
+    }
+    fragment {
+        vec4 main(VSOutput input) @ gl_FragColor {
+            // Simple fragment shader to display the result of the AND operation
+            return vec4(input.color.rgb, 1.0);
+        }
+    }
+}
+    """
+    try:
+        tokens = tokenize_code(code)
+        ast = parse_code(tokens)
+        generated_code = generate_code(ast)
+        print(generated_code)
+    except SyntaxError:
+        pytest.fail("Bitwise AND codegen not implemented")
+
+
+def test_double_data_type():
+    code = """
+    shader DoubleShader {
+        struct VSInput {
+            double texCoord @ TEXCOORD0;
+        };
+
+        struct VSOutput {
+            double color @ COLOR;
+        };
+
+        vertex {
+            VSOutput main(VSInput input) {
+                VSOutput output;
+                output.color = input.texCoord * 2.0;
+                return output;
+            }
+        }
+
+        fragment {
+            vec4 main(VSOutput input) @ gl_FragColor {
+                return vec4(input.color, 0.0, 0.0, 1.0);
+            }
+        }
+    }
+    """
+    try:
+        tokens = tokenize_code(code)
+        ast = parse_code(tokens)
+        generated_code = generate_code(ast)
+        print(generated_code)
+        assert "double" in generated_code
+    except SyntaxError:
+        pytest.fail("Double data type not supported.")
+
+
+# Test the codegen for the shift operators("<<", ">>")
+def test_shift_operators():
+    code = """
+    shader main {
+    
+    struct VSInput {
+        vec2 texCoord @ TEXCOORD0;
+    };
+
+    struct VSOutput {
+        vec4 color @ COLOR;
+    };
+
+    sampler2D iChannel0;
+
+    vertex {
+        VSOutput main(VSInput input) {
+            VSOutput output;
+            output.color = addColor(vec4(1.0, 1.0, 1.0, 1.0), vec4(0.5, 0.5, 0.5, 1.0));
+            uint a = 1 << 1;
+            uint b = 2 >> 1;
+            // Pass through texture coordinates as color
+            output.color = vec4(input.texCoord, 0.0, 1.0);
+            return output;
+        }
+    }
+
+    fragment {
+        vec4 main(VSOutput input) @ gl_FragColor {
+            // Sample brightness and calculate bloom
+            float brightness = texture(iChannel0, input.color.xy).r;
+            float bloom = max(0.0, brightness - 0.5);
+            // Apply bloom to the texture color
+            uint a = 1 << 1;
+            uint b = 2 >> 1;
+            vec3 texColor = texture(iChannel0, input.color.xy).rgb;
+            vec3 colorWithBloom = texColor + vec3(bloom);
+            return vec4(colorWithBloom, 1.0);
+        }
+    }
+    """
+
+    try:
+        tokens = tokenize_code(code)
+        ast = parse_code(tokens)
+        generated_code = generate_code(ast)
+        print(generated_code)
+    except SyntaxError:
+        pytest.fail("Shift right assignment operator codegen not implemented.")
+
+
 if __name__ == "__main__":
     pytest.main()
diff --git a/tests/test_translator/test_codegen/test_slang_codegen.py b/tests/test_translator/test_codegen/test_slang_codegen.py
new file mode 100644
index 00000000..9b315fe9
--- /dev/null
+++ b/tests/test_translator/test_codegen/test_slang_codegen.py
@@ -0,0 +1,43 @@
+from crosstl.src.translator.lexer import Lexer
+import pytest
+from typing import List
+from crosstl.src.translator.parser import Parser
+from crosstl.src.translator.codegen.slang_codegen import SlangCodeGen
+
+
+def tokenize_code(code: str) -> List:
+    """Helper function to tokenize code."""
+    lexer = Lexer(code)
+    return lexer.tokens
+
+
+def parse_code(tokens: List):
+    """Helper function to parse tokens into an AST.
+
+    Args:
+        tokens (List): The list of tokens to parse
+    Returns:
+        AST: The abstract syntax tree generated from the parser
+    """
+    parser = Parser(tokens)
+    return parser.parse()
+
+
+def generate_code(ast_node):
+    """Test the code generator
+    Args:
+        ast_node: The abstract syntax tree generated from the code
+    Returns:
+        str: The generated code from the abstract syntax tree
+    """
+    codegen = SlangCodeGen()
+    return codegen.generate(ast_node)
+
+
+# ToDO: Implement the tests
+def test_struct():
+    pass
+
+
+if __name__ == "__main__":
+    pytest.main()
diff --git a/tests/test_translator/test_parser.py b/tests/test_translator/test_parser.py
index 2bcd5c72..737e1d66 100644
--- a/tests/test_translator/test_parser.py
+++ b/tests/test_translator/test_parser.py
@@ -551,5 +551,40 @@ def test_xor_operator():
         pytest.fail("Bitwise XOR not working")
 
 
+def test_and_operator():
+    code = """
+    shader main {
+    struct VSInput {
+        vec2 texCoord @ TEXCOORD0;
+    };
+    struct VSOutput {
+        vec4 color @ COLOR;
+    };
+    sampler2D iChannel0;
+    vertex {
+        VSOutput main(VSInput input) {
+            VSOutput output;
+            // Use bitwise AND on texture coordinates (for testing purposes)
+            output.color = vec4(float(int(input.texCoord.x * 100.0) & 15), 
+                                float(int(input.texCoord.y * 100.0) & 15), 
+                                0.0, 1.0);
+            return output;
+        }
+    }
+    fragment {
+        vec4 main(VSOutput input) @ gl_FragColor {
+            // Simple fragment shader to display the result of the AND operation
+            return vec4(input.color.rgb, 1.0);
+        }
+    }
+}
+    """
+    try:
+        tokens = tokenize_code(code)
+        parse_code(tokens)
+    except SyntaxError:
+        pytest.fail("Bitwise AND not working")
+
+
 if __name__ == "__main__":
     pytest.main()