Repository: CrossGL/crosstl
Pull request #176 (2024-09-27 11:35:52)

chore: updated the translator frontend to new structure
### PR Description
<!-- Provide a brief summary of the changes you have made. Explain the purpose and motivation behind these changes. -->
updated the translator frontend parser directx codegen. 
### Related Issue
<!-- Link to the related issue(s) that this PR addresses. Example: #123 -->

### shader Sample
<!-- Provide a shader sample or snippet on which you have tested your changes. like

```crossgl
shader PerlinNoise {
    vertex {
        input vec3 position;
        output vec2 vUV;

        void main() {
            vUV = position.xy * 10.0;
            gl_Position = vec4(position, 1.0);
        }
    }

    // Perlin Noise Function
    float perlinNoise(vec2 p) {
        return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453);
    }

    // Fragment Shader
    fragment {
        input vec2 vUV;
        output vec4 fragColor;

        void main() {
            float noise = perlinNoise(vUV);
            float height = noise * 10.0;
            vec3 color = vec3(height / 10.0, 1.0 - height / 10.0, 0.0);
            fragColor = vec4(color, 1.0);
        }
    }
}
```-->


### Checklist
- [ ] Have you added the necessary tests?
- [ ] Only modified the files mentioned in the related issue(s)?
- [ ] Are all tests passing?





Patch:
diff --git a/.github/workflows/auto-assign-issues.yml b/.github/workflows/auto-assign-issues.yml
deleted file mode 100644
index 063f6d9..0000000
--- a/.github/workflows/auto-assign-issues.yml
+++ /dev/null
@@ -1,18 +0,0 @@
-name: Auto-Assign Issues
-
-on:
-  issue_comment:
-    types: [created]
-
-jobs:
-  assign_issue:
-    runs-on: ubuntu-latest
-    steps:
-    - name: Check if the comment is requesting assignment
-      if: github.event.comment.body == 'assign to me'
-      run: |
-        gh api \
-          -X POST \
-          -H "Accept: application/vnd.github+json" \
-          /repos/${{ github.repository }}/issues/${{ github.event.issue.number }}/assignees \
-          -d '{"assignees":["${{ github.event.comment.user.login }}"]}'
diff --git a/.github/workflows/stale-prs.yml b/.github/workflows/stale-prs.yml
new file mode 100644
index 0000000..fff4bb5
--- /dev/null
+++ b/.github/workflows/stale-prs.yml
@@ -0,0 +1,18 @@
+name: Close Stale Pull Requests
+
+on:
+  schedule:
+    - cron: '0 0 * * *'
+
+jobs:
+  close_stale_prs:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Close stale pull requests
+        uses: actions/stale@v9
+        with:
+          days-before-stale: 14
+          days-before-close: 7
+          stale-pr-message: 'This pull request has been marked as stale because it has been inactive for more than 14 days. Please update this pull request or it will be automatically closed in 7 days.'
+          stale-pr-label: stale
+          close-pr-message: 'This pull request has been automatically closed because it has been inactive for more than 14 days. Please reopen if you still intend to submit this pull request.'
diff --git a/.gitignore b/.gitignore
index fa77953..d679f83 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,10 @@
 __pycache__/
 .venv
 
+# msvc specific
+.vs
+build
+
 # Compiled Object files
 *.slo
 *.lo
@@ -36,4 +40,4 @@ __pycache__/
 /compiler/codegen/__pycache__
 /compiler/__pycache__
 *:Z*
-*workspace
\ No newline at end of file
+*workspace
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..cb862fb
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,88 @@
+
+# 🚀 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. 🎉
+
+## How to Contribute
+
+### 1. 🍴 Fork the Repository
+
+Start by forking the **crosstl** repository on GitHub to your own account.
+
+### 2. 🖥️ Clone Your Fork
+
+Clone your forked repository to your local machine:
+
+```bash
+git clone https://github.com/your-username/crosstl.git
+cd crosstl
+```
+
+### 3. 🌿 Create a Branch
+
+Create a new branch for your changes. Use a descriptive name for your branch:
+
+```bash
+git checkout -b feature-name
+```
+
+### 4. 🔧 Make Changes
+
+Make your changes to the codebase. Follow the project’s coding style and guidelines. Ensure that your changes do not break existing functionality.
+
+### 5. 🧪 Write Unit Tests
+
+Ensure that your code is reliable by writing unit tests:
+- Add tests for any new functionality or changes.
+- Make sure your code passes all existing and new tests.
+- You can run the test suite locally using:
+
+```bash
+pytest tests/
+```
+
+### 6. 💾 Commit Your Changes
+
+Commit your changes with a clear and concise commit message:
+
+```bash
+git add .
+git commit -m "Description of your changes"
+```
+
+### 7. 🚀 Push to GitHub
+
+Push your changes to your forked repository on GitHub:
+
+```bash
+git push origin feature-name
+```
+
+### 8. 🔄 Open a Pull Request
+
+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.
+
+## Contribution Pipeline
+
+### 🐛 Issue Tracking
+
+We use GitHub Issues to track bugs, enhancements, and tasks. Feel free to open a new issue if you find a bug or have a feature request. Please be sure to:
+- Provide a clear description.
+- Include steps to reproduce the issue if it’s a bug.
+- Suggest a solution if possible.
+
+### 👀 Code Review
+
+All contributions go through a code review process. The maintainers will review your pull request and provide feedback. Be prepared to make additional changes based on the feedback.
+
+### ✅ Continuous Integration (CI)
+
+We use Continuous Integration (CI) to run automated tests on all pull requests. Ensure that your code passes all the tests before submitting your pull request.
+
+### 🔗 Merging
+
+Once your pull request has been reviewed and approved, it will be merged into the main branch.
+
+## 🙏 Thank You ✨
+
+Thank you for your interest in contributing to **Crosstl**! Your contributions make a significant impact on the project and the community. Every contribution, big or small, helps us improve! 💖
diff --git a/README.md b/README.md
index c0fa7c5..f4f2465 100644
--- a/README.md
+++ b/README.md
@@ -271,7 +271,7 @@ We believe that everyone can contribute and make a difference. Whether
 it\'s writing code, fixing bugs, or simply sharing feedback,
 your contributions are definitely welcome and appreciated 🙌
 
-find out more info in our [Contributing guide](https://crossgl.github.io/contribution.html)
+find out more info in our [Contributing guide](CONTRIBUTING.md)
 
 <a href="https://github.com/CrossGL/crosstl/graphs/contributors">
   <img src="https://contrib.rocks/image?repo=CrossGL/crosstl" />
diff --git a/crosstl/src/backend/DirectX/DirectxCrossGLCodeGen.py b/crosstl/src/backend/DirectX/DirectxCrossGLCodeGen.py
index b84e3da..92f02b5 100644
--- a/crosstl/src/backend/DirectX/DirectxCrossGLCodeGen.py
+++ b/crosstl/src/backend/DirectX/DirectxCrossGLCodeGen.py
@@ -31,99 +31,34 @@ class HLSLToCrossGLConverter:
             "TextureCube": "samplerCube",
         }
         self.semantic_map = {
-            # Vertex inputs position
-            "POSITION": "in_Position",
-            "POSITION0": "in_Position0",
-            "POSITION1": "in_Position1",
-            "POSITION2": "in_Position2",
-            "POSITION3": "in_Position3",
-            "POSITION4": "in_Position4",
-            "POSITION5": "in_Position5",
-            "POSITION6": "in_Position6",
-            "POSITION7": "in_Position7",
-            # Vertex inputs normal
-            "NORMAL": "in_Normal",
-            "NORMAL0": "in_Normal0",
-            "NORMAL1": "in_Normal1",
-            "NORMAL2": "in_Normal2",
-            "NORMAL3": "in_Normal3",
-            "NORMAL4": "in_Normal4",
-            "NORMAL5": "in_Normal5",
-            "NORMAL6": "in_Normal6",
-            "NORMAL7": "in_Normal7",
-            # Vertex inputs tangent
-            "TANGENT": "in_Tangent",
-            "TANGENT0": "in_Tangent0",
-            "TANGENT1": "in_Tangent1",
-            "TANGENT2": "in_Tangent2",
-            "TANGENT3": "in_Tangent3",
-            "TANGENT4": "in_Tangent4",
-            "TANGENT5": "in_Tangent5",
-            "TANGENT6": "in_Tangent6",
-            "TANGENT7": "in_Tangent7",
-            # Vertex inputs binormal
-            "BINORMAL": "in_Binormal",
-            "BINORMAL0": "in_Binormal0",
-            "BINORMAL1": "in_Binormal1",
-            "BINORMAL2": "in_Binormal2",
-            "BINORMAL3": "in_Binormal3",
-            "BINORMAL4": "in_Binormal4",
-            "BINORMAL5": "in_Binormal5",
-            "BINORMAL6": "in_Binormal6",
-            "BINORMAL7": "in_Binormal7",
-            # Vertex inputs color
-            "COLOR": "Color",
-            "COLOR0": "Color0",
-            "COLOR1": "Color1",
-            "COLOR2": "Color2",
-            "COLOR3": "Color3",
-            "COLOR4": "Color4",
-            "COLOR5": "Color5",
-            "COLOR6": "Color6",
-            "COLOR7": "Color7",
-            # Vertex inputs texcoord
-            "TEXCOORD": "TexCoord",
-            "TEXCOORD0": "TexCoord0",
-            "TEXCOORD1": "TexCoord1",
-            "TEXCOORD2": "TexCoord2",
-            "TEXCOORD3": "TexCoord3",
-            "TEXCOORD4": "TexCoord4",
-            "TEXCOORD5": "TexCoord5",
-            "TEXCOORD6": "TexCoord6",
             # Vertex inputs instance
             "FRONT_FACE": "gl_IsFrontFace",
             "PRIMITIVE_ID": "gl_PrimitiveID",
-            "INSTANCE_ID": "gl_InstanceID",
-            "VERTEX_ID": "gl_VertexID",
+            "INSTANCE_ID": "InstanceID",
+            "VERTEX_ID": "VertexID",
+            "SV_InstanceID": "gl_InstanceID",
+            "SV_VertexID": "gl_VertexID",
             # Vertex outputs
-            "SV_Position": "Out_Position",
-            "SV_Position0": "Out_Position0",
-            "SV_Position1": "Out_Position1",
-            "SV_Position2": "Out_Position2",
-            "SV_Position3": "Out_Position3",
-            "SV_Position4": "Out_Position4",
-            "SV_Position5": "Out_Position5",
-            "SV_Position6": "Out_Position6",
-            "SV_Position7": "Out_Position7",
+            "SV_POSITION": "gl_Position",
             # Fragment inputs
-            "SV_Target": "Out_Color",
-            "SV_Target0": "Out_Color0",
-            "SV_Target1": "Out_Color1",
-            "SV_Target2": "Out_Color2",
-            "SV_Target3": "Out_Color3",
-            "SV_Target4": "Out_Color4",
-            "SV_Target5": "Out_Color5",
-            "SV_Target6": "Out_Color6",
-            "SV_Target7": "Out_Color7",
-            "SV_Depth": "Out_Depth",
-            "SV_Depth0": "Out_Depth0",
-            "SV_Depth1": "Out_Depth1",
-            "SV_Depth2": "Out_Depth2",
-            "SV_Depth3": "Out_Depth3",
-            "SV_Depth4": "Out_Depth4",
-            "SV_Depth5": "Out_Depth5",
-            "SV_Depth6": "Out_Depth6",
-            "SV_Depth7": "Out_Depth7",
+            "SV_TARGET": "gl_FragColor",
+            "SV_TARGET0": "gl_FragColor0",
+            "SV_TARGET1": "gl_FragColor1",
+            "SV_TARGET2": "gl_FragColor2",
+            "SV_TARGET3": "gl_FragColor3",
+            "SV_TARGET4": "gl_FragColor4",
+            "SV_TARGET5": "gl_FragColor5",
+            "SV_TARGET6": "gl_FragColor6",
+            "SV_TARGET7": "gl_FragColor7",
+            "SV_DEPTH": "gl_FragDepth",
+            "SV_DEPTH0": "gl_FragDepth0",
+            "SV_DEPTH1": "gl_FragDepth1",
+            "SV_DEPTH2": "gl_FragDepth2",
+            "SV_DEPTH3": "gl_FragDepth3",
+            "SV_DEPTH4": "gl_FragDepth4",
+            "SV_DEPTH5": "gl_FragDepth5",
+            "SV_DEPTH6": "gl_FragDepth6",
+            "SV_DEPTH7": "gl_FragDepth7",
         }
 
     def generate(self, ast):
diff --git a/crosstl/src/backend/Metal/MetalCrossGLCodeGen.py b/crosstl/src/backend/Metal/MetalCrossGLCodeGen.py
index 4de7d3d..955f65c 100644
--- a/crosstl/src/backend/Metal/MetalCrossGLCodeGen.py
+++ b/crosstl/src/backend/Metal/MetalCrossGLCodeGen.py
@@ -40,10 +40,10 @@ class MetalToCrossGLConverter:
         }
 
         self.map_semantics = {
-            "attribute(0)": "in_Position",
-            "attribute(1)": "in_Normal",
-            "attribute(2)": "in_Tangent",
-            "attribute(3)": "in_Binormal",
+            "attribute(0)": "Position",
+            "attribute(1)": "Normal",
+            "attribute(2)": "Tangent",
+            "attribute(3)": "Binormal",
             "attribute(4)": "TexCoord",
             "attribute(5)": "TexCoord0",
             "attribute(6)": "TexCoord1",
@@ -53,18 +53,18 @@ class MetalToCrossGLConverter:
             "instance_id": "gl_InstanceID",
             "base_vertex": "gl_BaseVertex",
             "base_instance": "gl_BaseInstance",
-            "position": "out_Position",
+            "position": "gl_Position",
             "point_size": "gl_PointSize",
             "clip_distance": "gl_ClipDistance",
             "front_facing": "gl_IsFrontFace",
             "point_coord": "gl_PointCoord",
-            "color(0)": "out_Color",
-            "color(1)": "out_Color1",
-            "color(2)": "out_Color2",
-            "color(3)": "out_Color3",
-            "color(4)": "out_Color4",
-            "depth(any)": "Out_Depth",
-            "stage_in": "gl_in",
+            "color(0)": "gl_FragColor",
+            "color(1)": "gl_FragColor1",
+            "color(2)": "gl_FragColor2",
+            "color(3)": "gl_FragColor3",
+            "color(4)": "gl_FragColor4",
+            "depth(any)": "gl_FragDepth",
+            "stage_in": "gl_FragColor",
         }
 
     def generate(self, ast):
diff --git a/crosstl/src/backend/Opengl/OpenglAst.py b/crosstl/src/backend/Opengl/OpenglAst.py
index c603a5c..025b702 100644
--- a/crosstl/src/backend/Opengl/OpenglAst.py
+++ b/crosstl/src/backend/Opengl/OpenglAst.py
@@ -34,14 +34,15 @@ class TernaryOpNode:
 
 
 class LayoutNode:
-    def __init__(self, location_number, dtype, name, io_type):
+    def __init__(self, location_number, dtype, name, io_type, semantic=None):
         self.location_number = location_number
         self.dtype = dtype
         self.name = name
         self.io_type = io_type
+        self.semantic = semantic
 
     def __repr__(self):
-        return f"LayoutNode(location_number={self.location_number}, dtype={self.dtype}, name={self.name}, io_type={self.io_type})"
+        return f"LayoutNode(location_number={self.location_number}, dtype={self.dtype}, name={self.name}, io_type={self.io_type}, semantic={self.semantic})"
 
 
 class ShaderNode(ASTNode):
@@ -81,13 +82,14 @@ class ArrayAccessNode(ASTNode):
 
 
 class VariableNode(ASTNode):
-    def __init__(self, vtype, name, io_type=None):
+    def __init__(self, vtype, name, io_type=None, semantic=None):
         self.vtype = vtype
         self.name = name
         self.io_type = io_type
+        self.semantic = semantic
 
     def __repr__(self):
-        return f"VariableNode(vtype='{self.vtype}', name='{self.name}', io_type={self.io_type})"
+        return f"VariableNode(vtype='{self.vtype}', name='{self.name}', io_type={self.io_type}, semantic={self.semantic})"
 
 
 class AssignmentNode(ASTNode):
diff --git a/crosstl/src/backend/Opengl/OpenglParser.py b/crosstl/src/backend/Opengl/OpenglParser.py
index 429cad8..44aeb31 100644
--- a/crosstl/src/backend/Opengl/OpenglParser.py
+++ b/crosstl/src/backend/Opengl/OpenglParser.py
@@ -3,10 +3,11 @@ from .OpenglLexer import *
 
 
 class GLSLParser:
-    def __init__(self, tokens, shader_type):
+    def __init__(self, tokens, shader_type="vertex"):
         self.tokens = tokens
         self.shader_type = shader_type
         self.pos = 0
+        self.main_count = 0
         self.current_token = self.tokens[self.pos]
         self.skip_comments()
 
@@ -15,6 +16,9 @@ class GLSLParser:
             self.eat(self.current_token[0])
 
     def eat(self, token_type):
+        if self.current_token[1] == "main" and self.shader_type == "vertex":
+            self.shader_type = "fragment"
+            # If we encounter the second 'main', switch shader_type to 'fragment'
         if self.current_token[0] == token_type:
             self.pos += 1
             self.current_token = (
@@ -60,7 +64,7 @@ class GLSLParser:
                 else:
                     global_variables.append(self.parse_global_variable())
             else:
-                self.eat(self.current_token[0])  # Skip unknown tokens
+                self.eat(self.current_token[0])  # Skip token
 
         return ShaderNode(
             io_variables,
@@ -181,7 +185,13 @@ class GLSLParser:
             if self.current_token[0] == "COMMA":
                 self.eat("COMMA")
         self.eat("SEMICOLON")
-        return LayoutNode(location_number, dtype, name, f"{self.shader_type}_{io_type}")
+        return LayoutNode(
+            location_number,
+            dtype,
+            name,
+            f"{self.shader_type}_{io_type}",
+            f"layout(location = {location_number})",
+        )
 
     def parse_uniform(self):
         self.eat("UNIFORM")
@@ -198,8 +208,7 @@ class GLSLParser:
         name = self.current_token[1]
         qualifier = None
         if name == "main":
-            qualifier = "main"
-
+            qualifier = self.shader_type
         self.eat("IDENTIFIER")
         self.eat("LPAREN")
         params = self.parse_parameters()
diff --git a/crosstl/src/backend/Opengl/openglCrossglCodegen.py b/crosstl/src/backend/Opengl/openglCrossglCodegen.py
index 622f3ac..fa9f39d 100644
--- a/crosstl/src/backend/Opengl/openglCrossglCodegen.py
+++ b/crosstl/src/backend/Opengl/openglCrossglCodegen.py
@@ -4,11 +4,42 @@ from .OpenglLexer import *
 
 
 class GLSLToCrossGLConverter:
-    def __init__(self, shader_type: str):
+    def __init__(self, shader_type="vertex"):
         self.shader_type = shader_type
         self.structures = {"VSInput": [], "PSOutput": [], "PSInput": [], "VSOutput": []}
         self.gl_position = False
         self.type_mapping = {}
+        self.semantic_map = {
+            "gl_VertexID": "gl_VertexID",
+            "gl_InstanceID": "gl_InstanceID",
+            "gl_FrontFacing": "gl_IsFrontFace",
+            "gl_PrimitiveID": "gl_PrimitiveID",
+            "layout(location = 8)": "TEXCOORD3",
+            "layout(location = 9)": "TEXCOORD4",
+            "layout(location = 10)": "TEXCOORD5",
+            "layout(location = 11)": "TEXCOORD6",
+            "layout(location = 12)": "TEXCOORD7",
+            "gl_Position": "gl_Position",
+            "gl_PointSize": "gl_PointSize",
+            "gl_ClipDistance": "gl_ClipDistance",
+            "layout(location = 0)": "gl_FragColor",
+            "layout(location = 1)": "gl_FragColor1",
+            "layout(location = 2)": "gl_FragColor2",
+            "layout(location = 3)": "gl_FragColor3",
+            "layout(location = 4)": "gl_FragColor4",
+            "layout(location = 5)": "gl_FragColor5",
+            "layout(location = 6)": "gl_FragColor6",
+            "layout(location = 7)": "gl_FragColor7",
+            "gl_FragDepth": "gl_FragDepth",
+            "gl_FragCoord": "gl_FragCoord",
+            "gl_PointCoord": "gl_PointCoord",
+            "gl_GlobalInvocationID": "gl_GlobalInvocationID",
+            "gl_LocalInvocationID": "gl_LocalInvocationID",
+            "gl_WorkGroupID": "gl_WorkGroupID",
+            "gl_LocalInvocationIndex": "gl_LocalInvocationIndex",
+            "gl_WorkGroupSize": "gl_WorkGroupSize",
+            "gl_NumWorkGroups": "gl_NumWorkGroups",
+        }
 
     def generate(self, ast):
         self.gl_position = False
@@ -17,7 +48,7 @@ class GLSLToCrossGLConverter:
         code += " \n"
         self.check_for_gl_position(ast)
         if self.gl_position:
-            self.structures["VSOutput"].append(("vec4", "position"))
+            self.structures["VSOutput"].append(("vec4", "position", None))
         for uniform in ast.uniforms:
             code += f"    cbuffer uniforms {{\n"
             if isinstance(uniform, UniformNode):
@@ -27,48 +58,52 @@ class GLSLToCrossGLConverter:
         for var in ast.io_variables:
             if isinstance(var, LayoutNode):
                 if var.io_type == "vertex_IN":
-                    self.structures["VSInput"].append((var.dtype, var.name))
+                    self.structures["VSInput"].append(
+                        (var.dtype, var.name, var.semantic)
+                    )
                 elif var.io_type == "vertex_OUT":
-                    self.structures["VSOutput"].append((var.dtype, var.name))
+                    self.structures["VSOutput"].append(
+                        (var.dtype, var.name, var.semantic)
+                    )
                 elif var.io_type == "fragment_IN":
-                    self.structures["PSInput"].append((var.dtype, var.name))
+                    self.structures["PSInput"].append(
+                        (var.dtype, var.name, var.semantic)
+                    )
                 elif var.io_type == "fragment_OUT":
-                    self.structures["PSOutput"].append((var.dtype, var.name))
+                    self.structures["PSOutput"].append(
+                        (var.dtype, var.name, var.semantic)
+                    )
             elif isinstance(var, VariableNode):
                 if var.io_type == "vertex_IN":
-                    self.structures["VSInput"].append((var.vtype, var.name))
+                    self.structures["VSInput"].append(
+                        (var.vtype, var.name, var.semantic)
+                    )
                 elif var.io_type == "vertex_OUT":
-                    self.structures["VSOutput"].append((var.vtype, var.name))
+                    self.structures["VSOutput"].append(
+                        (var.vtype, var.name, var.semantic)
+                    )
                 elif var.io_type == "fragment_IN":
-                    self.structures["PSInput"].append((var.vtype, var.name))
+                    self.structures["PSInput"].append(
+                        (var.vtype, var.name, var.semantic)
+                    )
                 elif var.io_type == "fragment_OUT":
-                    self.structures["PSOutput"].append((var.vtype, var.name))
+                    self.structures["PSOutput"].append(
+                        (var.vtype, var.name, var.semantic)
+                    )
             else:
                 raise ValueError("Invalid io type")
         for struct_name, members in self.structures.items():
             if members:
                 code += f"struct {struct_name} {{\n"
-                for i, (dtype, name) in enumerate(members):
+                for i, (dtype, name, semantic) in enumerate(members):
                     if struct_name == "VSInput":
-                        if i == 0:
-                            code += f"    {dtype} {name} @ in_position;\n"
-                        else:
-                            code += f"    {dtype} {name} @ TexCoord{i};\n"
+                        code += f"    {dtype} {name} {self.map_semantic(semantic,i)};\n"
                     elif struct_name == "VSOutput":
-                        if i == 0:
-                            code += f"    {dtype} {name} @ out_position;\n"
-                        else:
-                            code += f"    {dtype} {name} @ Color{i};\n"
+                        code += f"    {dtype} {name} {self.map_semantic(semantic,i)};\n"
                     elif struct_name == "PSInput":
-                        if i == 0:
-                            code += f"    {dtype} {name} @ Color;\n"
-                        else:
-                            code += f"    {dtype} {name} @ Color{i};\n"
+                        code += f"    {dtype} {name} {self.map_semantic(semantic,i)};\n"
                     elif struct_name == "PSOutput":
-                        if i == 0:
-                            code += f"    {dtype} {name} @ Out_Color;\n"
-                        else:
-                            code += f"    {dtype} {name} @ Out_Color{i};\n"
+                        code += f"    {dtype} {name} {self.map_semantic(semantic,i)};\n"
                 code += "};\n\n"
 
         for constant in ast.constant:
@@ -78,12 +113,7 @@ class GLSLToCrossGLConverter:
         for global_variable in ast.global_variables:
             code += f"    {global_variable.vtype} {global_variable.name};\n"
         for f in ast.functions:
-            if self.shader_type == "vertex":
-                code += self.generate_functions(f, "vertex")
-            elif self.shader_type == "fragment":
-                code += self.generate_functions(f, "fragment")
-            else:
-                raise ValueError("Invalid shader type")
+            code += self.generate_functions(f)
         code += "}\n"
         return code
 
@@ -100,39 +130,26 @@ class GLSLToCrossGLConverter:
                         ):
                             self.gl_position = True
 
-    def generate_functions(self, functions, shader_type):
+    def generate_functions(self, functions):
         code = ""
-        if shader_type == "vertex":
-            if functions.name == "main":
-                code += "vertex {\n"
-                code += "      VSOutput main(VSInput input) {\n"
-                code += "         VSOutput output;\n"
-            else:
-                params = ", ".join(
-                    f"{self.map_type(param[0])} {param[1]}"
-                    for param in functions.params
-                )
-                return_type = self.map_type(functions.return_type)
-                code += f"{return_type} {functions.name}({params}) {{\n"
-        elif shader_type == "fragment":
-            if functions.name == "main":
-                code += "fragment {\n"
-                if self.structures["PSInput"]:
-                    code += "       PSOutput main(PSInput input) {\n"
-                else:
-                    code += "       PSOutput main(VSOutput input) {\n"
-                code += "         PSOutput output;\n"
-            else:
-                params = ", ".join(
-                    f"{self.map_type(param[0])} {param[1]}"
-                    for param in functions.params
-                )
-                return_type = self.map_type(functions.return_type)
-                code += f"{return_type} {functions.name}({params}) {{\n"
+        if functions.qualifier == "vertex":
+            code += "vertex {\n"
+            code += "      VSOutput main(VSInput input) {\n"
+            code += "         VSOutput output;\n"
+        elif functions.qualifier == "fragment":
+            code += "fragment {\n"
+            code += "       PSOutput main(PSInput input) {\n"
+            code += "        PSOutput output;\n"
+        else:
+            params = ", ".join(
+                f"{self.map_type(param[0])} {param[1]}" for param in functions.params
+            )
+            return_type = self.map_type(functions.return_type)
+            code += f"{return_type} {functions.name}({params}) {{\n"
         for stmt in functions.body:
-            code += self.generate_statement(stmt, 2, shader_type)
+            code += self.generate_statement(stmt, 2)
         if functions.name == "main":
-            code += "            return output;\n"
+            code += "        return output;\n"
             code += "        }\n"
             code += "    }\n"
         else:
@@ -298,3 +315,9 @@ class GLSLToCrossGLConverter:
             "BITWISE_SHIFT_LEFT": "<<",
         }
         return op_map.get(op, op)
+
+    def map_semantic(self, semantic, i):
+        if semantic is not None:
+            return f"@ {self.semantic_map.get(semantic, semantic)}"
+        else:
+            return f"@ TEXCOORD{i}"
diff --git a/crosstl/src/translator/ast.py b/crosstl/src/translator/ast.py
index f8f2f0b..0ffa691 100644
--- a/crosstl/src/translator/ast.py
+++ b/crosstl/src/translator/ast.py
@@ -2,18 +2,6 @@ class ASTNode:
     pass
 
 
-class UniformNode(ASTNode):
-    def __init__(self, vtype, name):
-        self.vtype = vtype
-        self.name = name
-
-    def __repr__(self):
-        return f"UniformNode(vtype={self.vtype}, name={self.name})"
-
-    def __str__(self):
-        return f"uniform {self.vtype} {self.name};"
-
-
 class TernaryOpNode:
     def __init__(self, condition, true_expr, false_expr):
         self.condition = condition
@@ -25,75 +13,65 @@ class TernaryOpNode:
 
 
 class ShaderNode:
-    def __init__(
-        self,
-        name,
-        global_inputs,
-        global_outputs,
-        global_functions,
-        vertex_section,
-        fragment_section,
-    ):
-        self.name = name
-        self.global_inputs = global_inputs
-        self.global_outputs = global_outputs
-        self.global_functions = global_functions
-        self.vertex_section = vertex_section
-        self.fragment_section = fragment_section
+    def __init__(self, structs, functions, global_variables, cbuffers):
+        self.structs = structs
+        self.functions = functions
+        self.global_variables = global_variables
+        self.cbuffers = cbuffers
 
     def __repr__(self):
-        return f"ShaderNode({self.name!r}) {self.global_inputs!r} {self.global_outputs!r} {self.global_functions!r} {self.vertex_section!r} {self.fragment_section!r}"
+        return f"ShaderNode(structs={self.structs}, functions={self.functions}, global_variables={self.global_variables}, cbuffers={self.cbuffers})"
 
 
-class VERTEXShaderNode:
-    def __init__(self, inputs, outputs, functions, intermidiate):
-        self.inputs = inputs
-        self.outputs = outputs
-        self.functions = functions
-        self.intermidiate = intermidiate
+class StructNode:
+    def __init__(self, name, members):
+        self.name = name
+        self.members = members
 
     def __repr__(self):
-        return f"VERTEXShaderNode({self.inputs!r}) {self.outputs!r} {self.functions!r} {self.intermidiate!r}"
+        return f"StructNode(name={self.name}, members={self.members})"
 
 
-class FRAGMENTShaderNode:
-    def __init__(self, inputs, outputs, functions, intermidiate):
-        self.inputs = inputs
-        self.outputs = outputs
-        self.functions = functions
-        self.intermidiate = intermidiate
+class CbufferNode:
+    def __init__(self, name, members):
+        self.name = name
+        self.members = members
 
     def __repr__(self):
-        return f"FRAGMENTShaderNode({self.inputs!r}) {self.outputs!r} {self.functions!r} {self.intermidiate!r}"
+        return f"CbufferNode(name={self.name}, members={self.members})"
 
 
 class FunctionNode(ASTNode):
-    def __init__(self, return_type, name, params, body):
+    def __init__(self, return_type, name, params, body, qualifier=None, semantic=None):
         self.return_type = return_type
         self.name = name
         self.params = params
         self.body = body
+        self.qualifier = qualifier
+        self.semantic = semantic
 
     def __repr__(self):
-        return f"FunctionNode(return_type={self.return_type}, name={self.name}, params={self.params}, body={self.body})"
+        return f"FunctionNode(return_type={self.return_type}, name={self.name}, params={self.params}, body={self.body}, qualifier={self.qualifier}, semantic={self.semantic})"
 
 
 class VariableNode(ASTNode):
-    def __init__(self, vtype, name):
+    def __init__(self, vtype, name, semantic=None):
         self.vtype = vtype
         self.name = name
+        self.semantic = semantic
 
     def __repr__(self):
-        return f"VariableNode(vtype={self.vtype}, name={self.name})"
+        return f"VariableNode(vtype='{self.vtype}', name='{self.name}', semantic={self.semantic})"
 
 
 class AssignmentNode(ASTNode):
-    def __init__(self, name, value):
-        self.name = name
-        self.value = value
+    def __init__(self, left, right, operator="="):
+        self.left = left
+        self.right = right
+        self.operator = operator
 
     def __repr__(self):
-        return f"AssignmentNode(name={self.name}, value={self.value})"
+        return f"AssignmentNode(left={self.left}, operator='{self.operator}', right={self.right})"
 
 
 class IfNode(ASTNode):
diff --git a/crosstl/src/translator/codegen/directx_codegen.py b/crosstl/src/translator/codegen/directx_codegen.py
index cfd41bd..270b3a2 100644
--- a/crosstl/src/translator/codegen/directx_codegen.py
+++ b/crosstl/src/translator/codegen/directx_codegen.py
@@ -1,27 +1,20 @@
 from ..ast import (
-    ShaderNode,
     AssignmentNode,
-    FunctionNode,
-    ReturnNode,
     BinaryOpNode,
-    UnaryOpNode,
-    IfNode,
     ForNode,
-    VariableNode,
     FunctionCallNode,
+    IfNode,
     MemberAccessNode,
-    VERTEXShaderNode,
-    FRAGMENTShaderNode,
+    ReturnNode,
+    StructNode,
     TernaryOpNode,
+    UnaryOpNode,
+    VariableNode,
 )
 
 
 class HLSLCodeGen:
     def __init__(self):
-        self.current_shader = None
-        self.vertex_item = None
-        self.fragment_item = None
-        self.gl_position = False
         self.type_mapping = {
             "void": "void",
             "vec2": "float2",
@@ -46,307 +39,217 @@ class HLSLCodeGen:
             "double": "double",
             "sampler2D": "Texture2D",
             "samplerCube": "TextureCube",
+            "sampler": "SamplerState",
         }
 
-    def generate(self, ast):
-        if isinstance(ast, ShaderNode):
-            self.current_shader = ast
-            return self.generate_shader(ast)
-        return ""
+        self.semantic_map = {
+            # Vertex inputs instance
+            "gl_VertexID": "SV_VertexID",
+            "gl_InstanceID": "SV_InstanceID",
+            "gl_IsFrontFace": "FRONT_FACE",
+            "gl_PrimitiveID": "PRIMITIVE_ID",
+            "InstanceID": "INSTANCE_ID",
+            "VertexID": "VERTEX_ID",
+            # Vertex outputs
+            "gl_Position": "SV_POSITION",
+            "gl_PointSize": "SV_POINTSIZE",
+            "gl_ClipDistance": "SV_ClipDistance",
+            "gl_CullDistance": "SV_CullDistance",
+            # Fragment inputs
+            "gl_FragColor": "SV_TARGET",
+            "gl_FragColor0": "SV_TARGET0",
+            "gl_FragColor1": "SV_TARGET1",
+            "gl_FragColor2": "SV_TARGET2",
+            "gl_FragColor3": "SV_TARGET3",
+            "gl_FragColor4": "SV_TARGET4",
+            "gl_FragColor5": "SV_TARGET5",
+            "gl_FragColor6": "SV_TARGET6",
+            "gl_FragColor7": "SV_TARGET7",
+            "gl_FragDepth": "SV_DEPTH",
+            "gl_FragDepth0": "SV_DEPTH0",
+            "gl_FragDepth1": "SV_DEPTH1",
+            "gl_FragDepth2": "SV_DEPTH2",
+            "gl_FragDepth3": "SV_DEPTH3",
+        }
 
-    def generate_shader(self, node):
-        self.shader_inputs = node.global_inputs
-        self.shader_outputs = node.global_outputs
+    def generate(self, ast):
         code = "\n"
-        # Generate global inputs and outputs
-        if self.shader_inputs:
-            code += "struct VSINPUT {\n"
-            for i, (vtype, name) in enumerate(self.shader_inputs):
-                if i >= 1:
-                    code += f"    {self.map_type(vtype)} {name} : TEXCOORD{i};\n"
-                else:
-                    code += f"    {self.map_type(vtype)} {name} : POSITION{i};\n"
-            code += "};\n\n"
-
-        if self.shader_outputs:
-            code += "struct VSOUTPUT {\n"
-            for i, (vtype, name) in enumerate(self.shader_outputs):
-                code += f"    {self.map_type(vtype)} {name} : SV_TARGET{i};\n"
-            code += "};\n\n"
-
-        # Generate functions
-        for function in node.global_functions:
-            code += self.generate_function(function, "global") + "\n"
-
-        # Generate vertex shader section
-        self.vertex_item = node.vertex_section
-        if isinstance(self.vertex_item, VERTEXShaderNode):
-            shader_type = "vertex"
-            self.check_gl_position(self.vertex_item)
-            if self.vertex_item.inputs:
-                code += "struct VSInput {\n"
-                for i, (vtype, name) in enumerate(self.vertex_item.inputs):
-                    if i >= 1:
-                        code += f"    {self.map_type(vtype)} {name} : TEXCOORD{i-1};\n"
-                    else:
-                        code += f"    {self.map_type(vtype)} {name} : POSITION;\n"
-                code += "};\n\n"
-            if self.vertex_item.outputs:
-                code += "struct VSOutput {\n"
-                for i, (vtype, name) in enumerate(self.vertex_item.outputs):
-                    if self.gl_position:
-                        code += f"   float4 position : SV_POSITION;\n"
-                        self.gl_position = False
-                    code += f"    {self.map_type(vtype)} {name} : TEXCOORD{i};\n"
-                code += "};\n\n"
-
-            if self.vertex_item.functions:
-                code += f"{self.generate_function(self.vertex_item.functions, shader_type)}\n"
-
-            if self.vertex_item.intermidiate:
-                code += f"{self.generate_intermidiate(self.vertex_item.intermidiate, shader_type)}\n"
-            if self.vertex_item.functions:
-                for function_node in self.vertex_item.functions:
-                    if function_node.name == "main":
-                        code += f"{self.generate_main(function_node, shader_type)}\n"
-
-        # Generate fragment shader section
-        self.fragment_item = node.fragment_section
-        if isinstance(self.fragment_item, FRAGMENTShaderNode):
-            shader_type = "fragment"
-            if self.fragment_item.inputs:
-                code += "struct PSInput {\n"
-                for i, (vtype, name) in enumerate(self.fragment_item.inputs):
-                    code += f"    {self.map_type(vtype)} {name} : TEXCOORD{i};\n"
-                code += "};\n\n"
-            if self.fragment_item.outputs:
-                code += "struct PSOutput {\n"
-                for i, (vtype, name) in enumerate(self.fragment_item.outputs):
-                    code += f"    {self.map_type(vtype)} {name} : SV_TARGET{i};\n"
-                code += "};\n\n"
+        # Generate structs
+        for node in ast.structs:
+            if isinstance(node, StructNode):
+                code += f"struct {node.name} {{\n"
+                for member in node.members:
+                    code += f"    {self.map_type(member.vtype)} {member.name} {self.map_semantic(member.semantic)};\n"
+                code += "}\n"
+
+        # Generate global variables
+
+        for i, node in enumerate(ast.global_variables):
+            if node.vtype in ["sampler2D", "samplerCube"]:
+                code += "// Texture Samplers\n"
+                code += f"{self.map_type(node.vtype)} {node.name} :register(t{i});\n"
+            elif node.vtype in ["sampler"]:
+                code += "// Sampler States\n"
+                code += f"{self.map_type(node.vtype)} {node.name} :register(s{i});\n"
+            else:
+                code += f"{self.map_type(node.vtype)} {node.name};\n"
+        # Generate cbuffers
+        if ast.cbuffers:
+            code += "// Constant Buffers\n"
+            code += self.generate_cbuffers(ast)
+
+        # Generate custom functions
+        for func in ast.functions:
+            if func.qualifier == "vertex":
+                code += "// Vertex Shader\n"
+                code += self.generate_function(func, shader_type="vertex")
+            elif func.qualifier == "fragment":
+                code += "// Fragment Shader\n"
+                code += self.generate_function(func, shader_type="fragment")
+
+            elif func.qualifier == "compute":
+                code += "// Compute Shader\n"
+                code += self.generate_function(func, shader_type="compute")
+            else:
+                code += self.generate_function(func)
 
-            if self.fragment_item.functions:
-                code += f"{self.generate_function(self.fragment_item.functions, shader_type)}\n"
-            if self.fragment_item.intermidiate:
-                code += f"{self.generate_intermidiate(self.fragment_item.intermidiate, shader_type)}\n"
-            if self.fragment_item.functions:
-                for function_node in self.fragment_item.functions:
-                    if function_node.name == "main":
-                        code += f"{self.generate_main(function_node, shader_type)}\n"
         return code
 
-    def check_gl_position(self, node):
-        for function_node in self.vertex_item.functions:
-            for stmt in function_node.body:
-                vb_name = self.generate_statement(stmt)
-                vb_left = vb_name.split("=")[0].strip()
-                if vb_left == "output.position":
-                    self.gl_position = True
-
-    def generate_intermidiate(self, node, shader_type):
+    def generate_cbuffers(self, ast):
         code = ""
-        for stmt in node:
-            code += self.generate_statement(stmt, 0, shader_type=shader_type)
+        for i, node in enumerate(ast.cbuffers):
+            if isinstance(node, StructNode):
+                code += f"cbuffer {node.name} : register(b{i}){{\n"
+                for member in node.members:
+                    code += f"    {self.map_type(member.vtype)} {member.name};\n"
+                code += "}\n"
         return code
 
-    def generate_function(self, node, shader_type):
+    def generate_function(self, func, indent=0, shader_type=None):
         code = ""
+        code += "  " * indent
+        params = ", ".join(
+            f"{self.map_type(p.vtype)} {p.name} {self.map_semantic(p.semantic)}"
+            for p in func.params
+        )
         if shader_type == "vertex":
-            for function_node in node:
-                if function_node.name != "main":
-                    params = ", ".join(
-                        f"{self.map_type(param[0])} {param[1]}"
-                        for param in function_node.params
-                    )
-                    return_type = self.map_type(function_node.return_type)
-                    code += f"{return_type} {function_node.name}({params}) {{\n"
-
-                    for stmt in function_node.body:
-                        code += self.generate_statement(
-                            stmt, 1, shader_type=shader_type
-                        )
-
-                    code += "}\n"
+            code += f"{self.map_type(func.return_type)} VSMain({params}) {self.map_semantic(func.semantic)} {{\n"
         elif shader_type == "fragment":
-            for function_node in node:
-                if function_node.name != "main":
-                    params = ", ".join(
-                        f"{self.map_type(param[0])} {param[1]}"
-                        for param in function_node.params
-                    )
-                    return_type = self.map_type(function_node.return_type)
-                    code += f"{return_type} {function_node.name}({params}) {{\n"
-
-                    for stmt in function_node.body:
-                        code += self.generate_statement(
-                            stmt, 1, shader_type=shader_type
-                        )
-                    code += "}\n"
-        elif shader_type == "global":
-            if node.name == "main":
-                params = "Global_INPUT input"
-                return_type = "Global_OUTPUT"
-            else:
-                params = ", ".join(
-                    f"{self.map_type(param[0])} {param[1]}" for param in node.params
-                )
-                return_type = self.map_type(node.return_type)
-
-            code += f"{return_type} {node.name}({params}) {{\n"
-            if node.name == "main":
-                code += "    Global_OUTPUT output;\n"
-            for stmt in node.body:
-                code += self.generate_statement(stmt, 1, shader_type=shader_type)
-            if node.name == "main":
-                code += "    return output;\n"
-            code += "}\n"
-        return code
+            code += f"{self.map_type(func.return_type)} PSMain({params}) {self.map_semantic(func.semantic)} {{\n"
+        elif shader_type == "compute":
+            code += f"{self.map_type(func.return_type)} CSMain({params}) {self.map_semantic(func.semantic)} {{\n"
+        else:
+            code += f"{self.map_type(func.return_type)} {func.name}({params}) {self.map_semantic(func.semantic)} {{\n"
 
-    def generate_main(self, node, shader_type):
-        if shader_type == "vertex":
-            code = "VSOutput VSMain(VSInput input) {\n"
-            code += "    VSOutput output;\n"
-        elif shader_type == "fragment":
-            code = "PSOutput PSMain(PSInput input) {\n"
-            code += "    PSOutput output;\n"
-        for stmt in node.body:
-            code += self.generate_statement(stmt, 1, shader_type)
+        for stmt in func.body:
+            code += self.generate_statement(stmt, 1)
+        code += "}\n\n"
 
-        code += "    return output;\n"
-        code += "}\n"
         return code
 
-    def generate_statement(self, stmt, indent=0, shader_type=None):
+    def generate_statement(self, stmt, indent=0):
         indent_str = "    " * indent
         if isinstance(stmt, VariableNode):
             return f"{indent_str}{self.map_type(stmt.vtype)} {stmt.name};\n"
         elif isinstance(stmt, AssignmentNode):
-            return f"{indent_str}{self.generate_assignment(stmt, shader_type)};\n"
+            return f"{indent_str}{self.generate_assignment(stmt)};\n"
         elif isinstance(stmt, IfNode):
-            return self.generate_if(stmt, indent, shader_type)
+            return self.generate_if(stmt, indent)
         elif isinstance(stmt, ForNode):
-            return self.generate_for(stmt, indent, shader_type)
+            return self.generate_for(stmt, indent)
         elif isinstance(stmt, ReturnNode):
             code = ""
             for i, return_stmt in enumerate(stmt.value):
-                code += f"{self.generate_expression(return_stmt, shader_type)}"
+                code += f"{self.generate_expression(return_stmt)}"
                 if i < len(stmt.value) - 1:
                     code += ", "
             return f"{indent_str}return {code};\n"
         else:
-            return f"{indent_str}{self.generate_expression(stmt, shader_type)};\n"
+            return f"{indent_str}{self.generate_expression(stmt)};\n"
 
-    def generate_assignment(self, node, shader_type=None):
-        if shader_type in ["vertex", "fragment"] and isinstance(node.name, str):
-            if node.name in [
-                output[1] for output in getattr(self, f"{shader_type}_item").outputs
-            ]:
-                return f"output.{node.name} = {self.generate_expression(node.value, shader_type)}"
-        if isinstance(node.name, VariableNode) and node.name.vtype:
-            return f"{self.map_type(node.name.vtype)} {node.name.name} = {self.generate_expression(node.value, shader_type)}"
-        else:
-            lhs = self.generate_expression(node.name, shader_type)
-            if lhs == "gl_Position" or lhs == "gl_position":
-                return f"output.position = {self.generate_expression(node.value, shader_type)}"
-            return f"{lhs} = {self.generate_expression(node.value, shader_type)}"
+    def generate_assignment(self, node):
+        lhs = self.generate_expression(node.left)
+        rhs = self.generate_expression(node.right)
+        op = node.operator
+        return f"{lhs} {op} {rhs}"
 
-    def generate_if(self, node, indent, shader_type=None):
+    def generate_if(self, node, indent):
         indent_str = "    " * indent
-        code = f"{indent_str}if ({self.generate_expression(node.if_condition, shader_type)}) {{\n"
+        code = f"{indent_str}if ({self.generate_expression(node.if_condition)}) {{\n"
         for stmt in node.if_body:
-            code += self.generate_statement(stmt, indent + 1, shader_type)
+            code += self.generate_statement(stmt, indent + 1)
         code += f"{indent_str}}}"
 
         for else_if_condition, else_if_body in zip(
             node.else_if_conditions, node.else_if_bodies
         ):
-            code += f" else if ({self.generate_expression(else_if_condition, shader_type)}) {{\n"
+            code += f" else if ({self.generate_expression(else_if_condition)}) {{\n"
             for stmt in else_if_body:
-                code += self.generate_statement(stmt, indent + 1, shader_type)
+                code += self.generate_statement(stmt, indent + 1)
             code += f"{indent_str}}}"
 
         if node.else_body:
             code += " else {\n"
             for stmt in node.else_body:
-                code += self.generate_statement(stmt, indent + 1, shader_type)
+                code += self.generate_statement(stmt, indent + 1)
             code += f"{indent_str}}}"
         code += "\n"
         return code
 
-    def generate_for(self, node, indent, shader_type=None):
+    def generate_for(self, node, indent):
         indent_str = "    " * indent
 
-        init = self.generate_statement(node.init, 0, shader_type).strip()[
+        init = self.generate_statement(node.init, 0).strip()[
             :-1
         ]  # Remove trailing semicolon
 
-        condition = self.generate_statement(node.condition, 0, shader_type).strip()[
+        condition = self.generate_statement(node.condition, 0).strip()[
             :-1
         ]  # Remove trailing semicolon
 
-        update = self.generate_statement(node.update, 0, shader_type).strip()[:-1]
+        update = self.generate_statement(node.update, 0).strip()[:-1]
 
         code = f"{indent_str}for ({init}; {condition}; {update}) {{\n"
         for stmt in node.body:
-            code += self.generate_statement(stmt, indent + 1, shader_type)
+            code += self.generate_statement(stmt, indent + 1)
         code += f"{indent_str}}}\n"
         return code
 
-    def generate_expression(self, expr, shader_type=None):
+    def generate_expression(self, expr):
         if isinstance(expr, str):
-            return self.translate_expression(expr, shader_type)
+            return expr
         elif isinstance(expr, VariableNode):
-            if isinstance(expr.name, str):
-                return f"{self.map_type(expr.vtype)} {self.translate_expression(expr.name, shader_type)}"
-            else:
-                return f"{self.map_type(expr.vtype)} {self.generate_expression(expr.name, shader_type)}"
+            name = self.generate_expression(expr.name)
+            return f"{self.map_type(expr.vtype)} {name}"
         elif isinstance(expr, BinaryOpNode):
-            return f"{self.generate_expression(expr.left, shader_type)} {self.map_operator(expr.op)} {self.generate_expression(expr.right, shader_type)}"
-        elif isinstance(expr, FunctionCallNode):
-            args = ", ".join(
-                self.generate_expression(arg, shader_type) for arg in expr.args
-            )
-            if expr.name in self.type_mapping.keys():
-                return f"{self.map_type(expr.name)}({args})"
-            else:
-                func_name = self.translate_expression(expr.name, shader_type)
-                return f"{func_name}({args})"
+            left = self.generate_expression(expr.left)
+            right = self.generate_expression(expr.right)
+            return f"{left} {self.map_operator(expr.op)} {right}"
+
+        elif isinstance(expr, AssignmentNode):
+            left = self.generate_expression(expr.left)
+            right = self.generate_expression(expr.right)
+            return f"{left} {self.map_operator(expr.operator)} {right}"
+
         elif isinstance(expr, UnaryOpNode):
-            return f"{self.map_operator(expr.op)} {self.generate_expression(expr.operand, shader_type)}"
-        elif isinstance(expr, TernaryOpNode):
-            return f"{self.generate_expression(expr.condition, shader_type)} ? {self.generate_expression(expr.true_expr, shader_type)} : {self.generate_expression(expr.false_expr, shader_type)}"
+            operand = self.generate_expression(expr.operand)
+            return f"{self.map_operator(expr.op)}{operand}"
+        elif isinstance(expr, FunctionCallNode):
+            args = ", ".join(self.generate_expression(arg) for arg in expr.args)
+            return f"{expr.name}({args})"
         elif isinstance(expr, MemberAccessNode):
-            return f"{self.generate_expression(expr.object, shader_type)}.{expr.member}"
+            obj = self.generate_expression(expr.object)
+            return f"{obj}.{expr.member}"
+
+        elif isinstance(expr, TernaryOpNode):
+            return f"{self.generate_expression(expr.condition)} ? {self.generate_expression(expr.true_expr)} : {self.generate_expression(expr.false_expr)}"
         else:
             return str(expr)
 
-    def translate_expression(self, expr, shader_type):
-        if shader_type == "vertex":
-            if self.vertex_item and self.vertex_item.inputs:
-                for _, input_name in self.vertex_item.inputs:
-                    if expr == input_name:
-                        return f"input.{input_name}"
-            if self.vertex_item and self.vertex_item.outputs:
-                for _, output_name in self.vertex_item.outputs:
-                    if expr == output_name:
-                        return f"output.{output_name}"
-        elif shader_type == "fragment":
-            if self.fragment_item and self.fragment_item.inputs:
-                for _, input_name in self.fragment_item.inputs:
-                    if expr == input_name:
-                        return f"input.{input_name}"
-            if self.fragment_item and self.fragment_item.outputs:
-                for _, output_name in self.fragment_item.outputs:
-                    if expr == output_name:
-                        return f"output.{output_name}"
-
-        return self.type_mapping.get(expr, expr)
-
     def map_type(self, vtype):
-        if vtype == "":
-            return ""
-        else:
+        if vtype:
             return self.type_mapping.get(vtype, vtype)
+        return vtype
 
     def map_operator(self, op):
         op_map = {
@@ -372,7 +275,14 @@ class HLSLCodeGen:
             "OR": "||",
             "EQUALS": "=",
             "ASSIGN_SHIFT_LEFT": "<<=",
+            "ASSIGN_SHIFT_RIGHT": ">>=",
             "BITWISE_SHIFT_RIGHT": ">>",
             "BITWISE_SHIFT_LEFT": "<<",
         }
         return op_map.get(op, op)
+
+    def map_semantic(self, semantic):
+        if semantic is not None:
+            return f": {self.semantic_map.get(semantic, semantic)}"
+        else:
+            return ""
diff --git a/crosstl/src/translator/codegen/metal_codegen.py b/crosstl/src/translator/codegen/metal_codegen.py
index fe958af..94988ad 100644
--- a/crosstl/src/translator/codegen/metal_codegen.py
+++ b/crosstl/src/translator/codegen/metal_codegen.py
@@ -1,18 +1,15 @@
 from ..ast import (
-    ShaderNode,
     AssignmentNode,
-    FunctionNode,
-    ReturnNode,
     BinaryOpNode,
-    UnaryOpNode,
-    IfNode,
     ForNode,
-    VariableNode,
     FunctionCallNode,
-    TernaryOpNode,
+    IfNode,
     MemberAccessNode,
-    VERTEXShaderNode,
-    FRAGMENTShaderNode,
+    ReturnNode,
+    StructNode,
+    TernaryOpNode,
+    UnaryOpNode,
+    VariableNode,
 )
 
 
@@ -39,6 +36,8 @@ class MetalCodeGen:
         self.fragment_item = None
         self.gl_position = False
         self.char_mapper = CharTypeMapper()
+        self.texture_variables = []
+        self.sampler_variables = []
         self.type_mapping = {
             # Scalar Types
             "void": "void",
@@ -88,8 +87,8 @@ class MetalCodeGen:
             "bool2": "bool2",
             "bool3": "bool3",
             "bool4": "bool4",
-            "sampler2D": "Texture2D",
-            "samplerCube": "TextureCube",
+            "sampler2D": "texture2d<float>",
+            "samplerCube": "texturecube<float>",
             # Matrix Types
             "mat2": "float2x2",
             "mat3": "float3x3",
@@ -99,314 +98,243 @@ class MetalCodeGen:
             "half4x4": "half4x4",
         }
 
+        self.semantic_map = {
+            # Vertex inputs
+            "gl_VertexID": "vertex_id",
+            "gl_InstanceID": "instance_id",
+            "gl_IsFrontFace": "is_front_facing",
+            "gl_PrimitiveID": "primitive_id",
+            "POSITION": "attribute(0)",
+            "NORMAL": "attribute(1)",
+            "TANGENT": "attribute(2)",
+            "BINORMAL": "attribute(3)",
+            "TEXCOORD": "attribute(4)",
+            "TEXCOORD0": "attribute(5)",
+            "TEXCOORD1": "attribute(6)",
+            "TEXCOORD2": "attribute(7)",
+            "TEXCOORD3": "attribute(8)",
+            "TEXCOORD4": "attribute(9)",
+            "TEXCOORD5": "attribute(10)",
+            "TEXCOORD6": "attribute(11)",
+            "TEXCOORD7": "attribute(12)",
+            # Vertex outputs
+            "gl_Position": "position",
+            "gl_PointSize": "point_size",
+            "gl_ClipDistance": "clip_distance",
+            # Fragment inputs
+            "gl_FragColor": "[[color(0)]]",
+            "gl_FragColor0": "[[color(0)]]",
+            "gl_FragColor1": "[[color(1)]]",
+            "gl_FragColor2": "[[color(2)]]",
+            "gl_FragColor3": "[[color(3)]]",
+            "gl_FragColor4": "[[color(4)]]",
+            "gl_FragColor5": "[[color(5)]]",
+            "gl_FragColor6": "[[color(6)]]",
+            "gl_FragColor7": "[[color(7)]]",
+            "gl_FragDepth": "depth(any)",
+            # Additional Metal-specific attributes
+            "gl_FragCoord": "position",
+            "gl_FrontFacing": "is_front_facing",
+            "gl_PointCoord": "point_coord",
+            # Compute shader specific
+            "gl_GlobalInvocationID": "thread_position_in_grid",
+            "gl_LocalInvocationID": "thread_position_in_threadgroup",
+            "gl_WorkGroupID": "threadgroup_position_in_grid",
+            "gl_LocalInvocationIndex": "thread_index_in_threadgroup",
+            "gl_WorkGroupSize": "threadgroup_size",
+            "gl_NumWorkGroups": "threads_per_grid",
+        }
+
     def generate(self, ast):
-        if isinstance(ast, ShaderNode):
-            self.current_shader = ast
-            return self.generate_shader(ast)
-        return ""
-
-    def generate_shader(self, node):
-        self.shader_inputs = node.global_inputs
-        self.shader_outputs = node.global_outputs
-        code = "#include <metal_stdlib>\nusing namespace metal;\n\n"
-
-        # Generate global inputs and outputs
-        if self.shader_inputs:
-            code += "struct Global_INPUT {\n"
-            for i, (vtype, name) in enumerate(self.shader_inputs):
-                code += f"    {self.map_type(vtype)} {name} [[attribute({i})]];\n"
-            code += "};\n\n"
-
-        if self.shader_outputs:
-            code += "struct Global_OUTPUT {\n"
-            for i, (vtype, name) in enumerate(self.shader_outputs):
-                code += f"    {self.map_type(vtype)} {name} [[color({i})]];\n"
-            code += "};\n\n"
-
-        # Generate functions
-        for function in node.global_functions:
-            code += self.generate_function(function, "global") + "\n"
-
-        # Generate vertex shader section
-        self.vertex_item = node.vertex_section
-        if isinstance(self.vertex_item, VERTEXShaderNode):
-            shader_type = "vertex"
-            self.check_gl_position(self.vertex_item)
-            if self.vertex_item.inputs:
-                code += "struct Vertex_INPUT {\n"
-                for i, (vtype, name) in enumerate(self.vertex_item.inputs):
-                    code += f"    {self.map_type(vtype)} {name} [[attribute({i})]];\n"
-                code += "};\n\n"
-            if self.vertex_item.outputs:
-                code += "struct Vertex_OUTPUT {\n"
-                for i, (vtype, name) in enumerate(self.vertex_item.outputs):
-                    if self.gl_position:
-                        code += f"    float4 position [[position]];\n"
-                        self.gl_position = False
-                    code += f"    {self.map_type(vtype)} {name};\n"
-                code += "};\n\n"
-
-            if self.vertex_item.functions:
-                code += f"{self.generate_function(self.vertex_item.functions, shader_type)}\n"
-
-            if self.vertex_item.intermidiate:
-                code += f"{self.generate_intermidiate(self.vertex_item.intermidiate, shader_type)}\n"
-
-            if self.vertex_item.functions:
-                for function_node in self.vertex_item.functions:
-                    if function_node.name == "main":
-                        code += f"{self.generate_main(function_node, shader_type)}\n"
-
-        # Generate fragment shader section
-        self.fragment_item = node.fragment_section
-        if isinstance(self.fragment_item, FRAGMENTShaderNode):
-            shader_type = "fragment"
-            if self.fragment_item.inputs:
-                code += "struct Fragment_INPUT {\n"
-                for i, (vtype, name) in enumerate(self.fragment_item.inputs):
-                    if i == 0:
-                        code += f"    {self.map_type(vtype)} {name} [[stage_in]];\n"
-                    else:
-                        code += f"    {self.map_type(vtype)} {name};\n"
-                code += "};\n\n"
-            if self.fragment_item.outputs:
-                code += "struct Fragment_OUTPUT {\n"
-                for i, (vtype, name) in enumerate(self.fragment_item.outputs):
-                    code += f"    {self.map_type(vtype)} {name} [[color({i})]];\n"
-                code += "};\n\n"
-            if self.fragment_item.functions:
-                code += f"{self.generate_function(self.fragment_item.functions, shader_type)}\n"
-            if self.fragment_item.intermidiate:
-                code += f"{self.generate_intermidiate(self.fragment_item.intermidiate, shader_type)}\n"
-            if self.fragment_item.functions:
-                for function_node in self.fragment_item.functions:
-                    if function_node.name == "main":
-                        code += f"{self.generate_main(function_node, shader_type)}\n"
+        code = "\n"
+        code += "#include <metal_stdlib>\n"
+        code += "using namespace metal;\n"
+        code += "\n"
+        # Generate structs
+        for node in ast.structs:
+            if isinstance(node, StructNode):
+                code += f"struct {node.name} {{\n"
+                for member in node.members:
+                    code += f"    {self.map_type(member.vtype)} {member.name} {self.map_semantic(member.semantic)};\n"
+                code += "}\n"
+        # Generate global variables
+        for i, node in enumerate(ast.global_variables):
+            if node.vtype in ["sampler2D", "samplerCube"]:
+                self.texture_variables.append((node, i))
+            elif node.vtype in ["sampler"]:
+                self.sampler_variables.append((node, i))
+            else:
+                code += f"{self.map_type(node.vtype)} {node.name};\n"
+        # Generate cbuffers
+        if ast.cbuffers:
+            code += "// Constant Buffers\n"
+            code += self.generate_cbuffers(ast)
+
+        # Generate custom functions
+        for func in ast.functions:
+            if func.qualifier == "vertex":
+                code += "// Vertex Shader\n"
+                code += self.generate_function(func, shader_type="vertex")
+            elif func.qualifier == "fragment":
+                code += "// Fragment Shader\n"
+                code += self.generate_function(func, shader_type="fragment")
+
+            elif func.qualifier == "compute":
+                code += "// Compute Shader\n"
+                code += self.generate_function(func, shader_type="compute")
+            else:
+                code += self.generate_function(func)
 
         return code
 
-    def check_gl_position(self, node):
-        for function_node in self.vertex_item.functions:
-            for stmt in function_node.body:
-                vb_name = self.generate_statement(stmt)
-                vb_left = vb_name.split("=")[0].strip()
-                if vb_left == "output.position":
-                    self.gl_position = True
-
-    def generate_intermidiate(self, node, shader_type):
+    def generate_cbuffers(self, ast):
         code = ""
-        for stmt in node:
-            code += self.generate_statement(stmt, 0, shader_type=shader_type)
+        for node in ast.cbuffers:
+            if isinstance(node, StructNode):
+                code += f"{node.name} {{\n"
+                for member in node.members:
+                    code += f"    {self.map_type(member.vtype)} {member.name};\n"
+                code += "}\n"
+        for i, node in enumerate(ast.cbuffers):
+            if isinstance(node, StructNode):
+                code += f"constant {node.name} &{node.name} [[buffer({i})]];\n"
         return code
 
-    def generate_function(self, node, shader_type):
+    def generate_function(self, func, indent=0, shader_type=None):
         code = ""
-        if shader_type == "vertex":
-            for function_node in node:
-                if function_node.name != "main":
-                    params = ", ".join(
-                        f"{self.map_type(param[0])} {param[1]}"
-                        for param in function_node.params
-                    )
-                    return_type = self.map_type(function_node.return_type)
-                    code += f"{return_type} {function_node.name}({params}) {{\n"
+        code += "  " * indent
+        params = ", ".join(
+            f"{self.map_type(p.vtype)} {p.name} [[stage_in]]" for p in func.params
+        )
 
-                    for stmt in function_node.body:
-                        code += self.generate_statement(
-                            stmt, 1, shader_type=shader_type
-                        )
+        if shader_type == "vertex":
+            code += f"vertex {self.map_type(func.return_type)} vertex_{func.name}({params}) {{\n"
 
-                    code += "}\n"
         elif shader_type == "fragment":
-            for function_node in node:
-                if function_node.name != "main":
-                    params = ", ".join(
-                        f"{self.map_type(param[0])} {param[1]}"
-                        for param in function_node.params
+            if self.texture_variables:
+                for texture_variable, i in self.texture_variables:
+                    params += (
+                        f" , texture2d<float> {texture_variable.name} [[texture({i})]]"
                     )
-                    return_type = self.map_type(function_node.return_type)
-                    code += f"{return_type} {function_node.name}({params}) {{\n"
-                    for stmt in function_node.body:
-                        code += self.generate_statement(
-                            stmt, 1, shader_type=shader_type
-                        )
-
-                    code += "}\n"
-        elif shader_type == "global":
-            if node.name == "main":
-                params = "Global_INPUT input [[stage_in]]"
-                return_type = "Global_OUTPUT"
-            else:
-                params = ", ".join(
-                    f"{self.map_type(param[0])} {param[1]}" for param in node.params
-                )
-                return_type = self.map_type(node.return_type)
-
-            code = f"{return_type} {node.name}({params}) {{\n"
-            if node.name == "main":
-                code += "    Global_OUTPUT output;\n"
-            for stmt in node.body:
-                code += self.generate_statement(stmt, 1, shader_type=shader_type)
-            if node.name == "main":
-                code += "    return output;\n"
-            code += "}\n"
-        return code
+            if self.sampler_variables:
+                for sampler_variable, i in self.sampler_variables:
+                    params += f" , sampler {sampler_variable.name} [[sampler({i})]]"
+            code += f"fragment {self.map_type(func.return_type)} fragment_{func.name}({params}) {{\n"
 
-    def generate_main(self, node, shader_type):
-        if shader_type == "vertex":
-            code = "vertex Vertex_OUTPUT main(Vertex_INPUT input [[stage_in]]) {\n"
-            code += "    Vertex_OUTPUT output;\n"
-        if shader_type == "fragment":
-            code = (
-                "fragment Fragment_OUTPUT main(Fragment_INPUT input [[stage_in]]) {\n"
-            )
-            code += "    Fragment_OUTPUT output;\n"
+        elif shader_type == "compute":
+            code += f"kernel {self.map_type(func.return_type)} kernel_{func.name}({params}) {{\n"
+        else:
+            code += f"{self.map_type(func.return_type)} {func.name}({params}) {self.map_semantic(func.semantic)} {{\n"
+
+        for stmt in func.body:
+            code += self.generate_statement(stmt, 1)
+        code += "}\n\n"
 
-        for stmt in node.body:
-            code += self.generate_statement(stmt, 1, shader_type)
-        code += "    return output;\n"
-        code += "}\n"
         return code
 
-    def generate_statement(self, stmt, indent=0, shader_type=None):
+    def generate_statement(self, stmt, indent=0):
         indent_str = "    " * indent
         if isinstance(stmt, VariableNode):
             return f"{indent_str}{self.map_type(stmt.vtype)} {stmt.name};\n"
         elif isinstance(stmt, AssignmentNode):
-            return f"{indent_str}{self.generate_assignment(stmt, shader_type)};\n"
+            return f"{indent_str}{self.generate_assignment(stmt)};\n"
         elif isinstance(stmt, IfNode):
-            return self.generate_if(stmt, indent, shader_type)
+            return self.generate_if(stmt, indent)
         elif isinstance(stmt, ForNode):
-            return self.generate_for(stmt, indent, shader_type)
+            return self.generate_for(stmt, indent)
         elif isinstance(stmt, ReturnNode):
             code = ""
             for i, return_stmt in enumerate(stmt.value):
-                code += f"{self.generate_expression(return_stmt, shader_type)}"
+                code += f"{self.generate_expression(return_stmt)}"
                 if i < len(stmt.value) - 1:
                     code += ", "
             return f"{indent_str}return {code};\n"
         else:
-            return f"{indent_str}{self.generate_expression(stmt, shader_type)};\n"
-
-    def generate_assignment(self, node, shader_type=None):
-        if shader_type in ["vertex", "fragment"] and isinstance(node.name, str):
-            if node.name in [
-                output[1] for output in getattr(self, f"{shader_type}_item").outputs
-            ]:
-                return f"output.{node.name} = {self.generate_expression(node.value, shader_type)}"
-        if isinstance(node.name, VariableNode) and node.name.vtype:
-            return f"{self.map_type(node.name.vtype)} {node.name.name} = {self.generate_expression(node.value, shader_type)}"
-        else:
-            lhs = self.generate_expression(node.name, shader_type)
-            if lhs == "gl_Position" or lhs == "gl_position":
-                return f"output.position = {self.generate_expression(node.value, shader_type)}"
-            return f"{lhs} = {self.generate_expression(node.value, shader_type)}"
+            return f"{indent_str}{self.generate_expression(stmt)};\n"
+
+    def generate_assignment(self, node):
+        lhs = self.generate_expression(node.left)
+        rhs = self.generate_expression(node.right)
+        op = node.operator
+        return f"{lhs} {op} {rhs}"
 
-    def generate_if(self, node, indent, shader_type=None):
+    def generate_if(self, node, indent):
         indent_str = "    " * indent
-        code = f"{indent_str}if ({self.generate_expression(node.if_condition, shader_type)}) {{\n"
+        code = f"{indent_str}if ({self.generate_expression(node.if_condition)}) {{\n"
         for stmt in node.if_body:
-            code += self.generate_statement(stmt, indent + 1, shader_type)
+            code += self.generate_statement(stmt, indent + 1)
         code += f"{indent_str}}}"
 
         for else_if_condition, else_if_body in zip(
             node.else_if_conditions, node.else_if_bodies
         ):
-            code += f" else if ({self.generate_expression(else_if_condition, shader_type)}) {{\n"
+            code += f" else if ({self.generate_expression(else_if_condition)}) {{\n"
             for stmt in else_if_body:
-                code += self.generate_statement(stmt, indent + 1, shader_type)
+                code += self.generate_statement(stmt, indent + 1)
             code += f"{indent_str}}}"
 
         if node.else_body:
             code += " else {\n"
             for stmt in node.else_body:
-                code += self.generate_statement(stmt, indent + 1, shader_type)
+                code += self.generate_statement(stmt, indent + 1)
             code += f"{indent_str}}}"
         code += "\n"
         return code
 
-    def generate_for(self, node, indent, shader_type=None):
+    def generate_for(self, node, indent):
         indent_str = "    " * indent
 
-        init = self.generate_statement(node.init, 0, shader_type).strip()[
+        init = self.generate_statement(node.init, 0).strip()[
             :-1
         ]  # Remove trailing semicolon
 
-        condition = self.generate_statement(node.condition, 0, shader_type).strip()[
+        condition = self.generate_statement(node.condition, 0).strip()[
             :-1
         ]  # Remove trailing semicolon
 
-        update = self.generate_statement(node.update, 0, shader_type).strip()[:-1]
+        update = self.generate_statement(node.update, 0).strip()[:-1]
 
         code = f"{indent_str}for ({init}; {condition}; {update}) {{\n"
         for stmt in node.body:
-            code += self.generate_statement(stmt, indent + 1, shader_type)
+            code += self.generate_statement(stmt, indent + 1)
         code += f"{indent_str}}}\n"
         return code
 
-    def generate_expression(self, expr, shader_type=None):
+    def generate_expression(self, expr):
         if isinstance(expr, str):
-            return self.translate_expression(expr, shader_type)
+            return expr
         elif isinstance(expr, VariableNode):
-            if isinstance(expr.name, str):
-                return f"{self.map_type(expr.vtype)} {self.translate_expression(expr.name, shader_type)}"
-            else:
-                return f"{self.map_type(expr.vtype)} {self.generate_expression(expr.name, shader_type)}"
+            name = self.generate_expression(expr.name)
+            return f"{self.map_type(expr.vtype)} {name}"
         elif isinstance(expr, BinaryOpNode):
-            return f"{self.generate_expression(expr.left, shader_type)} {self.map_operator(expr.op)} {self.generate_expression(expr.right, shader_type)}"
-        elif isinstance(expr, FunctionCallNode):
-            args = ", ".join(
-                self.generate_expression(arg, shader_type) for arg in expr.args
-            )
-            if expr.name in self.type_mapping.keys():
-                return f"{self.map_type(expr.name)}({args})"
-            else:
-                func_name = self.translate_expression(expr.name, shader_type)
-                return f"{func_name}({args})"
+            left = self.generate_expression(expr.left)
+            right = self.generate_expression(expr.right)
+            return f"{left} {self.map_operator(expr.op)} {right}"
 
-        elif isinstance(expr, UnaryOpNode):
-            return f"{self.map_operator(expr.op)}{self.generate_expression(expr.operand, shader_type)}"
-
-        elif isinstance(expr, TernaryOpNode):
-            return f"{self.generate_expression(expr.condition, shader_type)} ? {self.generate_expression(expr.true_expr, shader_type)} : {self.generate_expression(expr.false_expr, shader_type)}"
+        elif isinstance(expr, AssignmentNode):
+            left = self.generate_expression(expr.left)
+            right = self.generate_expression(expr.right)
+            return f"{left} {self.map_operator(expr.operator)} {right}"
 
+        elif isinstance(expr, UnaryOpNode):
+            operand = self.generate_expression(expr.operand)
+            return f"{self.map_operator(expr.op)}{operand}"
+        elif isinstance(expr, FunctionCallNode):
+            args = ", ".join(self.generate_expression(arg) for arg in expr.args)
+            return f"{expr.name}({args})"
         elif isinstance(expr, MemberAccessNode):
+            obj = self.generate_expression(expr.object)
+            return f"{obj}.{expr.member}"
 
-            return f"{self.generate_expression(expr.object, shader_type)}.{expr.member}"
-
+        elif isinstance(expr, TernaryOpNode):
+            return f"{self.generate_expression(expr.condition)} ? {self.generate_expression(expr.true_expr)} : {self.generate_expression(expr.false_expr)}"
         else:
             return str(expr)
 
-    def translate_expression(self, expr, shader_type):
-        if shader_type == "vertex":
-            if self.vertex_item and self.vertex_item.inputs:
-                for _, input_name in self.vertex_item.inputs:
-                    if expr == input_name:
-                        return f"input.{input_name}"
-            if self.vertex_item and self.vertex_item.outputs:
-                for _, output_name in self.vertex_item.outputs:
-                    if expr == output_name:
-                        return f"output.{output_name}"
-        elif shader_type == "fragment":
-            if self.fragment_item and self.fragment_item.inputs:
-                for _, input_name in self.fragment_item.inputs:
-                    if expr == input_name:
-                        return f"input.{input_name}"
-            if self.fragment_item and self.fragment_item.outputs:
-                for _, output_name in self.fragment_item.outputs:
-                    if expr == output_name:
-                        return f"output.{output_name}"
-
-        return self.type_mapping.get(expr, expr)
-
     def map_type(self, vtype):
-        if vtype == "":
-            return ""
-        else:
-            mapped_type = self.char_mapper.map_char_type(vtype)
-            if mapped_type != vtype:
-                return mapped_type
+        if vtype:
             return self.type_mapping.get(vtype, vtype)
+        return vtype
 
     def map_operator(self, op):
         op_map = {
@@ -416,6 +344,7 @@ class MetalCodeGen:
             "DIVIDE": "/",
             "BITWISE_XOR": "^",
             "LESS_THAN": "<",
+            "GREATER_THAN": ">",
             "ASSIGN_ADD": "+=",
             "ASSIGN_SUB": "-=",
             "ASSIGN_OR": "|=",
@@ -423,7 +352,6 @@ class MetalCodeGen:
             "ASSIGN_DIV": "/=",
             "ASSIGN_MOD": "%=",
             "ASSIGN_XOR": "^=",
-            "GREATER_THAN": ">",
             "LESS_EQUAL": "<=",
             "GREATER_EQUAL": ">=",
             "EQUAL": "==",
@@ -432,7 +360,14 @@ class MetalCodeGen:
             "OR": "||",
             "EQUALS": "=",
             "ASSIGN_SHIFT_LEFT": "<<=",
+            "ASSIGN_SHIFT_RIGHT": ">>=",
             "BITWISE_SHIFT_RIGHT": ">>",
             "BITWISE_SHIFT_LEFT": "<<",
         }
         return op_map.get(op, op)
+
+    def map_semantic(self, semantic):
+        if semantic is not None:
+            return f" [[{self.semantic_map.get(semantic, semantic)}]]"
+        else:
+            return ""
diff --git a/crosstl/src/translator/codegen/opengl_codegen.py b/crosstl/src/translator/codegen/opengl_codegen.py
index 317b7f6..048c261 100644
--- a/crosstl/src/translator/codegen/opengl_codegen.py
+++ b/crosstl/src/translator/codegen/opengl_codegen.py
@@ -1,267 +1,253 @@
 from ..ast import (
-    ShaderNode,
     AssignmentNode,
-    FunctionNode,
-    ReturnNode,
     BinaryOpNode,
-    UnaryOpNode,
-    IfNode,
     ForNode,
-    VariableNode,
     FunctionCallNode,
+    IfNode,
     MemberAccessNode,
-    VERTEXShaderNode,
-    FRAGMENTShaderNode,
+    ReturnNode,
+    StructNode,
     TernaryOpNode,
+    UnaryOpNode,
+    VariableNode,
 )
 
 
 class GLSLCodeGen:
     def __init__(self):
-        self.current_shader = None
-        self.vertex_item = None
-        self.fragment_item = None
+        self.semantic_map = {
+            "gl_VertexID": "gl_VertexID",
+            "gl_InstanceID": "gl_InstanceID",
+            "gl_IsFrontFace": "gl_FrontFacing",
+            "gl_PrimitiveID": "gl_PrimitiveID",
+            "POSITION": "layout(location = 0)",
+            "NORMAL": "layout(location = 1)",
+            "TANGENT": "layout(location = 2)",
+            "BINORMAL": "layout(location = 3)",
+            "TEXCOORD": "layout(location = 4)",
+            "TEXCOORD0": "layout(location = 5)",
+            "TEXCOORD1": "layout(location = 6)",
+            "TEXCOORD2": "layout(location = 7)",
+            "TEXCOORD3": "layout(location = 8)",
+            "TEXCOORD4": "layout(location = 9)",
+            "TEXCOORD5": "layout(location = 10)",
+            "TEXCOORD6": "layout(location = 11)",
+            "TEXCOORD7": "layout(location = 12)",
+            # Vertex outputs
+            "gl_Position": "gl_Position",
+            "gl_PointSize": "gl_PointSize",
+            "gl_ClipDistance": "gl_ClipDistance",
+            # Fragment outputs
+            "gl_FragColor": "layout(location = 0)",
+            "gl_FragColor1": "layout(location = 1)",
+            "gl_FragColor2": "layout(location = 2)",
+            "gl_FragColor3": "layout(location = 3)",
+            "gl_FragColor4": "layout(location = 4)",
+            "gl_FragColor5": "layout(location = 5)",
+            "gl_FragColor6": "layout(location = 6)",
+            "gl_FragColor7": "layout(location = 7)",
+            "gl_FragDepth": "gl_FragDepth",
+            # Additional fragment inputs
+            "gl_FragCoord": "gl_FragCoord",
+            "gl_FrontFacing": "gl_FrontFacing",
+            "gl_PointCoord": "gl_PointCoord",
+            # Compute shader specific
+            "gl_GlobalInvocationID": "gl_GlobalInvocationID",
+            "gl_LocalInvocationID": "gl_LocalInvocationID",
+            "gl_WorkGroupID": "gl_WorkGroupID",
+            "gl_LocalInvocationIndex": "gl_LocalInvocationIndex",
+            "gl_WorkGroupSize": "gl_WorkGroupSize",
+            "gl_NumWorkGroups": "gl_NumWorkGroups",
+        }
 
     def generate(self, ast):
-        if isinstance(ast, ShaderNode):
-            self.current_shader = ast
-            return self.generate_shader(ast)
-        return ""
-
-    def generate_shader(self, node):
-        self.shader_inputs = node.global_inputs
-        self.shader_outputs = node.global_outputs
-        code = "#version 450\n\n"
-
-        # Generate global inputs and outputs
-        for i, (vtype, name) in enumerate(self.shader_inputs):
-            code += f"layout(location = {i}) in {self.map_type(vtype)} {name};\n"
-        for i, (vtype, name) in enumerate(self.shader_outputs):
-            code += f"layout(location = {i}) out {self.map_type(vtype)} {name};\n"
-        code += "\n"
-
-        # Generate functions
-        code += "// Vertex shader\n\n"
-        for function in node.global_functions:
-            code += self.generate_function(function, "global") + "\n"
-
-        # Generate vertex shader section
-        self.vertex_item = node.vertex_section
-        if isinstance(self.vertex_item, VERTEXShaderNode):
-            shader_type = "vertex"
-            if self.vertex_item.inputs:
-                for i, (vtype, name) in enumerate(self.vertex_item.inputs):
-                    code += (
-                        f"layout(location = {i}) in {self.map_type(vtype)} {name};\n"
-                    )
-
-            if self.vertex_item.outputs:
-                for i, (vtype, name) in enumerate(self.vertex_item.outputs):
-                    if i == 0:
-                        code += f"out {self.map_type(vtype)} {name};\n"
-                    else:
-                        code += f"layout(location = {i-1}) out {self.map_type(vtype)} {name};\n"
-                code += "\n"
-
-            if self.vertex_item.functions:
-                code += f"{self.generate_function(self.vertex_item.functions, shader_type)}\n"
-
-            if self.vertex_item.intermidiate:
-                code += f"{self.generate_intermidiate(self.vertex_item.intermidiate, shader_type)}\n"
-
-            if self.vertex_item.functions:
-                for function_node in self.vertex_item.functions:
-                    if function_node.name == "main":
-                        code += f"{self.generate_main(function_node, shader_type)}\n"
-
-        # Generate fragment shader section
-        self.fragment_item = node.fragment_section
-        if isinstance(self.fragment_item, FRAGMENTShaderNode):
-            code += "\n// Fragment shader\n\n"
-            shader_type = "fragment"
-            if self.fragment_item.inputs:
-                for i, (vtype, name) in enumerate(self.fragment_item.inputs):
-                    if i == 0:
-                        code += f"in {self.map_type(vtype)} {name};\n"
-                    else:
-                        code += f"layout(location = {i-1}) in {self.map_type(vtype)} {name};\n"
-            if self.fragment_item.outputs:
-                for i, (vtype, name) in enumerate(self.fragment_item.outputs):
-                    code += (
-                        f"layout(location = {i}) out {self.map_type(vtype)} {name};\n"
-                    )
-                code += "\n"
+        code = "\n"
+        code += "#version 450 core\n"
+        # Generate structs
+        for node in ast.structs:
+            if isinstance(node, StructNode):
+                if node.name == "VSInput":
+                    for member in node.members:
+                        code += f"{self.map_semantic(member.semantic)} in {member.vtype} {member.name};\n"
+                elif node.name == "VSOutput":
+                    for member in node.members:
+                        code += f"out {member.vtype} {member.name};\n"
+                elif node.name == "PSInput":
+                    for member in node.members:
+                        code += f"in {member.vtype} {member.name};\n"
+                elif node.name == "PSOutput":
+                    for member in node.members:
+                        code += f"{self.map_semantic(member.semantic)} out {member.vtype} {member.name};\n"
+                else:
+                    code = ""
+                    code += f"struct {node.name} {{\n"
+                    for member in node.members:
+                        code += f"    {self.map_type(member.vtype)} {member.name};\n"
+                    code += "}\n"
 
-            if self.fragment_item.functions:
-                code += f"{self.generate_function(self.fragment_item.functions, shader_type)}\n"
-            if self.fragment_item.intermidiate:
-                code += f"{self.generate_intermidiate(self.fragment_item.intermidiate, shader_type)}\n"
-            if self.fragment_item.functions:
-                for function_node in self.fragment_item.functions:
-                    if function_node.name == "main":
-                        code += f"{self.generate_main(function_node, shader_type)}\n"
+        # Generate global variables
+        for i, node in enumerate(ast.global_variables):
+            code += f"layout(std140, binding = {i}) {self.map_type(node.vtype)} {node.name};\n"
+        # Generate cbuffers
+        if ast.cbuffers:
+            code += "// Constant Buffers\n"
+            code += self.generate_cbuffers(ast)
+
+        # Generate custom functions
+        for func in ast.functions:
+            if func.qualifier == "vertex":
+                code += "// Vertex Shader\n"
+                code += self.generate_function(func, shader_type="vertex")
+            elif func.qualifier == "fragment":
+                code += "// Fragment Shader\n"
+                code += self.generate_function(func, shader_type="fragment")
+
+            elif func.qualifier == "compute":
+                code += "// Compute Shader\n"
+                code += self.generate_function(func, shader_type="compute")
+            else:
+                code += self.generate_function(func)
 
         return code
 
-    def generate_function(self, node, shader_type):
+    def generate_cbuffers(self, ast):
         code = ""
-        if shader_type in ["vertex", "fragment"]:
-            for function_node in node:
-                if function_node.name != "main":
-                    params = ", ".join(
-                        f"{self.map_type(param[0])} {param[1]}"
-                        for param in function_node.params
-                    )
-                    code += f"{self.map_type(function_node.return_type)} {function_node.name}({params}) {{\n"
-                    for stmt in function_node.body:
-                        code += self.generate_statement(
-                            stmt, 1, shader_type=shader_type
-                        )
-                    code += "}\n"
-        elif shader_type == "global":
-            params = ", ".join(
-                f"{self.map_type(param[0])} {param[1]}" for param in node.params
-            )
-            code = f"{self.map_type(node.return_type)} {node.name}({params}) {{\n"
-            for stmt in node.body:
-                code += self.generate_statement(stmt, 1, shader_type=shader_type)
-            code += "}\n"
+        for i, node in enumerate(ast.cbuffers):
+            if isinstance(node, StructNode):
+                code += f"layout(std140, binding = {i}) uniform {node.name} {{\n"
+                for member in node.members:
+                    code += f"    {self.map_type(member.vtype)} {member.name};\n"
+                code += "}\n"
         return code
 
-    def generate_main(self, node, shader_type):
+    def generate_function(self, func, indent=0, shader_type=None):
         code = ""
+        code += "  " * indent
         params = ", ".join(
-            f"{self.map_type(param[0])} {param[1]}" for param in node.params
+            f"{self.map_type(p.vtype)} {p.name} {self.map_semantic(p.semantic)}"
+            for p in func.params
         )
-        code += f"{self.map_type(node.return_type)} {node.name}({params}) {{\n"
-        for stmt in node.body:
-            code += self.generate_statement(stmt, 1, shader_type=shader_type)
-        code += "}\n"
+        if shader_type == "vertex":
+            code += f"void main(){{\n"
+        elif shader_type == "fragment":
+            code += f"void main() {{\n"
+        elif shader_type == "compute":
+            code += f"void main() {{\n"
+        else:
+            code += f"{self.map_type(func.return_type)} {func.name}({params}) {{\n"
+
+        for stmt in func.body:
+            code += self.generate_statement(stmt, 1)
+        code += "}\n\n"
+
         return code
 
-    def generate_statement(self, stmt, indent=0, shader_type=None):
+    def generate_statement(self, stmt, indent=0, is_main=False):
         indent_str = "    " * indent
         if isinstance(stmt, VariableNode):
             return f"{indent_str}{self.map_type(stmt.vtype)} {stmt.name};\n"
         elif isinstance(stmt, AssignmentNode):
-            return f"{indent_str}{self.generate_assignment(stmt, shader_type)};\n"
+            return f"{indent_str}{self.generate_assignment(stmt, is_main)};\n"
         elif isinstance(stmt, IfNode):
-            return self.generate_if(stmt, indent, shader_type)
+            return self.generate_if(stmt, indent, is_main)
         elif isinstance(stmt, ForNode):
-            return self.generate_for(stmt, indent, shader_type)
+            return self.generate_for(stmt, indent, is_main)
         elif isinstance(stmt, ReturnNode):
             code = ""
             for i, return_stmt in enumerate(stmt.value):
-                code += f"{self.generate_expression(return_stmt, shader_type)}"
+                code += f"{self.generate_expression(return_stmt, is_main)}"
                 if i < len(stmt.value) - 1:
                     code += ", "
             return f"{indent_str}return {code};\n"
         else:
-            return f"{indent_str}{self.generate_expression(stmt, shader_type)};\n"
-
-    def generate_intermidiate(self, node, shader_type):
-        code = ""
-        for stmt in node:
-            code += self.generate_statement(stmt, 0, shader_type=shader_type)
-        return code
-
-    def generate_assignment(self, node, shader_type=None):
-        if isinstance(node.name, VariableNode) and node.name.vtype:
-            return f"{self.map_type(node.name.vtype)} {node.name.name} = {self.generate_expression(node.value, shader_type)}"
-        else:
-            lhs = self.generate_expression(node.name, shader_type)
-            return f"{lhs} = {self.generate_expression(node.value, shader_type)}"
-
-    def generate_if(self, node, indent, shader_type=None):
+            return f"{indent_str}{self.generate_expression(stmt, is_main)};\n"
+
+    def generate_assignment(self, node, is_main):
+        lhs = self.generate_expression(node.left, is_main)
+        rhs = self.generate_expression(node.right, is_main)
+        op = self.map_operator(node.operator)
+        if is_main and isinstance(node.left, MemberAccessNode):
+            if node.left.object == "output" and node.left.member == "position":
+                return f"gl_Position = {rhs}"
+            elif node.left.object in ["input", "output"]:
+                return f"{node.left.member} = {rhs}"
+        return f"{lhs} {op} {rhs}"
+
+    def generate_if(self, node, indent, is_main):
         indent_str = "    " * indent
-        code = f"{indent_str}if ({self.generate_expression(node.if_condition, shader_type)}) {{\n"
+        code = f"{indent_str}if ({self.generate_expression(node.if_condition)}) {{\n"
         for stmt in node.if_body:
-            code += self.generate_statement(stmt, indent + 1, shader_type)
+            code += self.generate_statement(stmt, indent + 1)
         code += f"{indent_str}}}"
 
         for else_if_condition, else_if_body in zip(
             node.else_if_conditions, node.else_if_bodies
         ):
-            code += f" else if ({self.generate_expression(else_if_condition, shader_type)}) {{\n"
+            code += f" else if ({self.generate_expression(else_if_condition)}) {{\n"
             for stmt in else_if_body:
-                code += self.generate_statement(stmt, indent + 1, shader_type)
+                code += self.generate_statement(stmt, indent + 1)
             code += f"{indent_str}}}"
 
         if node.else_body:
             code += " else {\n"
             for stmt in node.else_body:
-                code += self.generate_statement(stmt, indent + 1, shader_type)
+                code += self.generate_statement(stmt, indent + 1)
             code += f"{indent_str}}}"
         code += "\n"
         return code
 
-    def generate_for(self, node, indent, shader_type=None):
+    def generate_for(self, node, indent, is_main):
         indent_str = "    " * indent
 
-        init = self.generate_statement(node.init, 0, shader_type).strip()[
+        init = self.generate_statement(node.init, 0).strip()[
             :-1
         ]  # Remove trailing semicolon
 
-        condition = self.generate_statement(node.condition, 0, shader_type).strip()[
+        condition = self.generate_statement(node.condition, 0).strip()[
             :-1
         ]  # Remove trailing semicolon
 
-        update = self.generate_statement(node.update, 0, shader_type).strip()[:-1]
+        update = self.generate_statement(node.update, 0).strip()[:-1]
 
         code = f"{indent_str}for ({init}; {condition}; {update}) {{\n"
         for stmt in node.body:
-            code += self.generate_statement(stmt, indent + 1, shader_type)
+            code += self.generate_statement(stmt, indent + 1)
         code += f"{indent_str}}}\n"
         return code
 
-    def generate_expression(self, expr, shader_type=None):
+    def generate_expression(self, expr, is_main=False):
         if isinstance(expr, str):
-            return self.translate_expression(expr, shader_type)
+            return expr
         elif isinstance(expr, VariableNode):
-            if isinstance(expr.name, str):
-                return f"{self.map_type(expr.vtype)} {self.translate_expression(expr.name, shader_type)}"
-            else:
-                return f"{self.map_type(expr.vtype)} {self.generate_expression(expr.name, shader_type)}"
+            name = self.generate_expression(expr.name, is_main)
+            return f"{self.map_type(expr.vtype)} {name}"
         elif isinstance(expr, BinaryOpNode):
-            return f"{self.generate_expression(expr.left, shader_type)} {self.map_operator(expr.op)} {self.generate_expression(expr.right, shader_type)}"
+            left = self.generate_expression(expr.left, is_main)
+            right = self.generate_expression(expr.right, is_main)
+            return f"{left} {self.map_operator(expr.op)} {right}"
+        elif isinstance(expr, AssignmentNode):
+            return self.generate_assignment(expr, is_main)
+        elif isinstance(expr, UnaryOpNode):
+            operand = self.generate_expression(expr.operand, is_main)
+            return f"{self.map_operator(expr.op)}{operand}"
         elif isinstance(expr, FunctionCallNode):
             args = ", ".join(
-                self.generate_expression(arg, shader_type) for arg in expr.args
+                self.generate_expression(arg, is_main) for arg in expr.args
             )
-            func_name = self.translate_expression(expr.name, shader_type)
-            return f"{func_name}({args})"
-        elif isinstance(expr, UnaryOpNode):
-            return f"{self.map_operator(expr.op)}{self.generate_expression(expr.operand, shader_type)}"
-
-        elif isinstance(expr, TernaryOpNode):
-            return f"{self.generate_expression(expr.condition, shader_type)} ? {self.generate_expression(expr.true_expr, shader_type)} : {self.generate_expression(expr.false_expr, shader_type)}"
+            return f"{expr.name}({args})"
         elif isinstance(expr, MemberAccessNode):
-            return f"{self.generate_expression(expr.object, shader_type)}.{expr.member}"
+            if is_main and expr.object in ["input", "output"]:
+                return expr.member
+            obj = self.generate_expression(expr.object, is_main)
+            return f"{obj}.{expr.member}"
+        elif isinstance(expr, TernaryOpNode):
+            condition = self.generate_expression(expr.condition, is_main)
+            true_expr = self.generate_expression(expr.true_expr, is_main)
+            false_expr = self.generate_expression(expr.false_expr, is_main)
+            return f"{condition} ? {true_expr} : {false_expr}"
         else:
             return str(expr)
 
-    def translate_expression(self, expr, shader_type):
-        if shader_type == "vertex":
-            if self.vertex_item and self.vertex_item.inputs:
-                for _, input_name in self.vertex_item.inputs:
-                    if expr == input_name:
-                        return input_name
-            if self.vertex_item and self.vertex_item.outputs:
-                for _, output_name in self.vertex_item.outputs:
-                    if expr == output_name:
-                        return output_name
-        elif shader_type == "fragment":
-            if self.fragment_item and self.fragment_item.inputs:
-                for _, input_name in self.fragment_item.inputs:
-                    if expr == input_name:
-                        return input_name
-            if self.fragment_item and self.fragment_item.outputs:
-                for _, output_name in self.fragment_item.outputs:
-                    if expr == output_name:
-                        return output_name
-
-        return expr
-
     def map_type(self, vtype):
         return vtype
 
@@ -273,6 +259,7 @@ class GLSLCodeGen:
             "DIVIDE": "/",
             "BITWISE_XOR": "^",
             "LESS_THAN": "<",
+            "GREATER_THAN": ">",
             "ASSIGN_ADD": "+=",
             "ASSIGN_SUB": "-=",
             "ASSIGN_OR": "|=",
@@ -280,7 +267,6 @@ class GLSLCodeGen:
             "ASSIGN_DIV": "/=",
             "ASSIGN_MOD": "%=",
             "ASSIGN_XOR": "^=",
-            "GREATER_THAN": ">",
             "LESS_EQUAL": "<=",
             "GREATER_EQUAL": ">=",
             "EQUAL": "==",
@@ -288,8 +274,19 @@ class GLSLCodeGen:
             "AND": "&&",
             "OR": "||",
             "EQUALS": "=",
+            "MOD": "%",
+            "BITWISE_OR": "|",
+            "BITWISE_AND": "&",
+            "BITWISE_XOR": "^",
             "ASSIGN_SHIFT_LEFT": "<<=",
+            "ASSIGN_SHIFT_RIGHT": ">>=",
             "BITWISE_SHIFT_RIGHT": ">>",
             "BITWISE_SHIFT_LEFT": "<<",
         }
         return op_map.get(op, op)
+
+    def map_semantic(self, semantic):
+        if semantic is not None:
+            return f"{self.semantic_map.get(semantic, semantic)}"
+        else:
+            return ""
diff --git a/crosstl/src/translator/codegen/vulkan_codegen.py b/crosstl/src/translator/codegen/vulkan_codegen.py
index 3212172..f247eec 100644
--- a/crosstl/src/translator/codegen/vulkan_codegen.py
+++ b/crosstl/src/translator/codegen/vulkan_codegen.py
@@ -1,14 +1,13 @@
 from ..ast import (
-    ShaderNode,
     AssignmentNode,
-    FunctionNode,
-    ReturnNode,
     BinaryOpNode,
-    IfNode,
     ForNode,
-    VariableNode,
     FunctionCallNode,
+    IfNode,
     MemberAccessNode,
+    ReturnNode,
+    ShaderNode,
+    VariableNode,
 )
 
 
diff --git a/crosstl/src/translator/lexer.py b/crosstl/src/translator/lexer.py
index 5b84282..a4faa41 100644
--- a/crosstl/src/translator/lexer.py
+++ b/crosstl/src/translator/lexer.py
@@ -4,11 +4,12 @@ TOKENS = [
     ("COMMENT_SINGLE", r"//.*"),
     ("COMMENT_MULTI", r"/\*[\s\S]*?\*/"),
     ("SHADER", r"\bshader\b"),
-    ("INPUT", r"\binput\b"),
-    ("OUTPUT", r"\boutput\b"),
     ("VOID", r"\bvoid\b"),
-    ("MAIN", r"\bmain\b"),
-    ("UNIFORM", r"\buniform\b"),
+    ("STRUCT", r"\bstruct\b"),
+    ("CBUFFER", r"\bcbuffer\b"),
+    ("AT", r"\@"),
+    ("SAMPLER2D", r"\bsampler2D\b"),
+    ("SAMPLERCUBE", r"\bsamplerCube\b"),
     ("VECTOR", r"\bvec[2-4]\b"),
     ("MATRIX", r"\bmat[2-4]\b"),
     ("BOOL", r"\bbool\b"),
@@ -19,7 +20,7 @@ TOKENS = [
     ("INT", r"\bint\b"),
     ("UINT", r"\buint\b"),
     ("DOUBLE", r"\bdouble\b"),
-    ("SAMPLER2D", r"\bsampler2D\b"),
+    ("SAMPLER", r"\bsampler\b"),
     ("IDENTIFIER", r"[a-zA-Z_][a-zA-Z_0-9]*"),
     ("ASSIGN_SHIFT_RIGHT", r">>="),
     ("ASSIGN_SHIFT_LEFT", r"<<="),
@@ -76,10 +77,7 @@ TOKENS = [
 
 KEYWORDS = {
     "shader": "SHADER",
-    "input": "INPUT",
-    "output": "OUTPUT",
     "void": "VOID",
-    "main": "MAIN",
     "vertex": "VERTEX",
     "fragment": "FRAGMENT",
     "if": "IF",
diff --git a/crosstl/src/translator/parser.py b/crosstl/src/translator/parser.py
index 83f0daa..4e4fb1c 100644
--- a/crosstl/src/translator/parser.py
+++ b/crosstl/src/translator/parser.py
@@ -1,21 +1,18 @@
-# compiler/parser.py
-
 from .ast import (
-    ShaderNode,
-    FunctionNode,
-    AssignmentNode,
-    IfNode,
+    BinaryOpNode,
+    CbufferNode,
     ForNode,
-    ReturnNode,
     FunctionCallNode,
-    BinaryOpNode,
+    FunctionNode,
+    IfNode,
     MemberAccessNode,
-    VariableNode,
-    UniformNode,
-    UnaryOpNode,
+    ReturnNode,
+    ShaderNode,
+    StructNode,
     TernaryOpNode,
-    VERTEXShaderNode,
-    FRAGMENTShaderNode,
+    UnaryOpNode,
+    VariableNode,
+    AssignmentNode,
 )
 
 from .lexer import Lexer
@@ -69,45 +66,6 @@ class Parser:
         else:
             raise SyntaxError(f"Expected {token_type}, got {self.current_token[0]}")
 
-    def parse_uniforms(self):
-        """Parse uniform declarations
-
-        This method parses uniform declarations in the shader code.
-        It consumes the "UNIFORM" token and then parses the uniform type and name.
-        The method returns a list of UniformNode objects.
-
-        Returns:
-            list: A list of UniformNode objects
-
-        Raises:
-            SyntaxError: If the current token is not "UNIFORM"
-
-        """
-
-        uniforms = []
-        while self.current_token[0] == "UNIFORM":
-            self.eat("UNIFORM")
-            if self.current_token[0] in [
-                "VECTOR",
-                "FLOAT",
-                "DOUBLE",
-                "UINT",
-                "INT",
-                "SAMPLER2D",
-                "MATRIX",
-            ]:
-                vtype = self.current_token[1]
-                self.eat(self.current_token[0])
-            else:
-                raise SyntaxError(
-                    f"Expected VECTOR, FLOAT, DOUBLE, UINT, INT or SAMPLER2D, got {self.current_token[0]}"
-                )
-            name = self.current_token[1]
-            self.eat("IDENTIFIER")
-            self.eat("SEMICOLON")
-            uniforms.append(UniformNode(vtype, name))
-        return uniforms
-
     def parse(self):
         """Parse the shader code
 
@@ -120,309 +78,145 @@ class Parser:
         return self.parse_shader()
 
     def parse_shader(self):
-        """Parse the shader code
-
-        This method parses the shader code and generates a ShaderNode object.
-
-        Returns:
-            ShaderNode: The root node of the AST
-
-        Raises:
-            SyntaxError: If the current token is not "SHADER"
-
-        """
-        self.eat("SHADER")
-        self.skip_comments()  # Skip comments after eating SHADER
-        if self.current_token[0] in ("IDENTIFIER", "MAIN"):
-            shader_name = self.current_token[1]
-            self.eat(self.current_token[0])
-            self.skip_comments()
-        else:
-            raise SyntaxError(
-                f"Expected IDENTIFIER or MAIN, got {self.current_token[0]}"
-            )
-        self.eat("LBRACE")
-
-        global_inputs = self.parse_inputs()
-        self.parse_uniforms()
-        global_outputs = self.parse_outputs()
-
-        global_functions = []
-
-        vertex_section = None
-        fragment_section = None
-
-        while self.current_token[0] != "RBRACE":
-            if self.current_token[0] == "VERTEX":
-                vertex_section = self.parse_shader_section("VERTEX")
-                self.skip_comments()  # Skip comments while parsing functions
-            elif self.current_token[0] == "FRAGMENT":
-                fragment_section = self.parse_shader_section("FRAGMENT")
-                self.skip_comments()  # Skip comments while parsing functions
+        functions = []
+        structs = []
+        cbuffers = []
+        global_variables = []
+        while self.current_token[0] != "EOF":
+            if self.current_token[0] == "SHADER":
+                self.eat("SHADER")
+                self.eat("IDENTIFIER")
+                self.eat("LBRACE")
+            if self.current_token[0] == "STRUCT":
+                structs.append(self.parse_struct())
+            elif self.current_token[0] == "CBUFFER":
+                cbuffers.append(self.parse_cbuffer())
+            elif self.current_token[1] in ["vertex", "fragment"]:
+                functions.append(self.parse_main_function())
+                self.eat("RBRACE")
             elif self.current_token[0] in [
-                "VECTOR",
+                "VOID",
                 "FLOAT",
+                "VECTOR",
                 "DOUBLE",
                 "UINT",
                 "INT",
-                "VOID",
                 "MATRIX",
+                "IDENTIFIER",
+                "SAMPLER2D",
+                "SAMPLERCUBE",
+                "SAMPLER",
             ]:
-                global_functions.append(self.parse_function())
-                self.skip_comments()  # Skip comments while parsing functions
+                if self.is_function():
+                    functions.append(self.parse_function())
+                else:
+                    global_variables.append(self.parse_global_variable())
             else:
-                raise SyntaxError(f"Unexpected token: {self.current_token[0]}")
-
-        self.eat("RBRACE")
-        return ShaderNode(
-            shader_name,
-            global_inputs,
-            global_outputs,
-            global_functions,
-            vertex_section,
-            fragment_section,
-        )
-
-    def parse_shader_section(self, section_type):
-        """Parse a shader section
-
-        This method parses a shader section (VERTEX or FRAGMENT) and generates a VERTEXShaderNode or FRAGMENTShaderNode object.
-
-        Args:
-            section_type (str): The type of shader section (VERTEX or FRAGMENT)
-
-        Returns:
-            VERTEXShaderNode or FRAGMENTShaderNode: The root node of the AST for the shader section
+                self.eat(self.current_token[0])  # Skip unknown tokens
 
-        Raises:
-            SyntaxError: If the current token is not "VERTEX" or "FRAGMENT"
+        return ShaderNode(structs, functions, global_variables, cbuffers)
 
-        """
-        self.eat(section_type)
+    def parse_global_variable(self):
+        var_type = self.current_token[1]
+        self.eat(self.current_token[0])
+        var_name = self.current_token[1]
+        self.eat("IDENTIFIER")
+        self.eat("SEMICOLON")
+        return VariableNode(var_type, var_name)
+
+    def is_function(self):
+        current_pos = self.pos
+        while self.tokens[current_pos][0] != "EOF":
+            if self.tokens[current_pos][0] == "LPAREN":
+                return True
+            if self.tokens[current_pos][0] == "SEMICOLON":
+                return False
+            current_pos += 1
+        return False
+
+    def parse_cbuffer(self):
+        self.eat("CBUFFER")
+        name = self.current_token[1]
+        self.eat("IDENTIFIER")
         self.eat("LBRACE")
-        functions = []
-        intermidiate = []
-        inputs = []
-        outputs = []
+        members = []
         while self.current_token[0] != "RBRACE":
-            if self.current_token[0] == "UNIFORM":
-                self.parse_uniforms()
-            elif self.current_token[0] == "INPUT":
-                inputs.extend(self.parse_inputs())
-            elif self.current_token[0] == "OUTPUT":
-                outputs.extend(self.parse_outputs())
-            elif (
-                self.current_token[0]
-                in ["VECTOR", "FLOAT", "DOUBLE", "UINT", "INT", "VOID", "MATRIX"]
-                and self.peak(2)[0] == "LPAREN"
-            ):
-                functions.append(self.parse_function())
-            elif self.current_token[0] == "FOR":
-                intermidiate.append(self.parse_for_loop())
-            elif self.current_token[0] == "IF":
-                intermidiate.append(self.parse_if_statement())
-            elif self.current_token[0] in [
-                "VECTOR",
-                "IDENTIFIER",
-                "FLOAT",
-                "DOUBLE",
-                "UINT",
-                "INT",
-                "MATRIX",
-            ]:
-                intermidiate.append(self.parse_assignment_or_function_call())
-            else:
-                raise SyntaxError(f"Unexpected token {self.current_token[0]}")
-        self.eat("RBRACE")
-        if section_type == "VERTEX":
-            return VERTEXShaderNode(inputs, outputs, functions, intermidiate)
-        else:
-            return FRAGMENTShaderNode(inputs, outputs, functions, intermidiate)
-
-    def parse_inputs(self):
-        """Parse input declarations
-
-        This method parses input declarations in the shader code.
-
-        Returns:
-
-            list: A list of input declarations
-
-
-        Raises:
-
-            SyntaxError: If the current token is not "INPUT"
-
-
-        """
-        inputs = []
-        while self.current_token[0] == "INPUT":
-            self.eat("INPUT")
-            if self.current_token[0] in [
-                "VECTOR",
-                "FLOAT",
-                "DOUBLE",
-                "UINT",
-                "INT",
-                "MATRIX",
-                "SAMPLER2D",
-            ]:
-                vtype = self.current_token[1]
-                self.eat(self.current_token[0])
-            else:
-                raise SyntaxError(
-                    f"Expected VECTOR, FLOAT, DOUBLE, UINT, INT, MATRIX, or SAMPLER2D, got {self.current_token[0]}"
-                )
-            name = self.current_token[1]
+            vtype = self.current_token[1]
+            self.eat(self.current_token[0])
+            var_name = self.current_token[1]
             self.eat("IDENTIFIER")
+            if self.current_token[0] == "LBRACKET":
+                self.eat("LBRACKET")
+                size = self.current_token[1]
+                self.eat("NUMBER")
+                self.eat("RBRACKET")
+                var_name += f"[{size}]"
             self.eat("SEMICOLON")
-            inputs.append((vtype, name))
-        return inputs
-
-    def parse_outputs(self):
-        """Parse output declarations
-
-        This method parses output declarations in the shader code.
-
-        Returns:
-
-            list: A list of output declarations
-
-
-        Raises:
-
-            SyntaxError: If the current token is not "OUTPUT"
+            members.append(VariableNode(vtype, var_name))
+        self.eat("RBRACE")
+        return CbufferNode(name, members)
 
-        """
-        outputs = []
-        while self.current_token[0] == "OUTPUT":
-            self.eat("OUTPUT")
-            if self.current_token[0] in [
-                "VECTOR",
-                "FLOAT",
-                "DOUBLE",
-                "UINT",
-                "INT",
-                "MATRIX",
-                "SAMPLER2D",
-            ]:
-                vtype = self.current_token[1]
-                self.eat(self.current_token[0])
-            else:
-                raise SyntaxError(
-                    f"Expected VECTOR, FLOAT, DOUBLE, UINT, INT, MATRIX, or SAMPLER2D, got {self.current_token[0]}"
-                )
-            name = self.current_token[1]
+    def parse_struct(self):
+        self.eat("STRUCT")
+        name = self.current_token[1]
+        self.eat("IDENTIFIER")
+        self.eat("LBRACE")
+        members = []
+        while self.current_token[0] != "RBRACE":
+            vtype = self.current_token[1]
+            self.eat(self.current_token[0])
+            var_name = self.current_token[1]
             self.eat("IDENTIFIER")
+            semantic = None
+            if self.current_token[0] == "AT":
+                self.eat("AT")
+                semantic = self.current_token[1]
+                self.eat("IDENTIFIER")
             self.eat("SEMICOLON")
-            outputs.append((vtype, name))
-        return outputs
-
-    def parse_function(self):
-        """Parse a function declaration
-
-        This method parses a function declaration in the shader code.
-
-        Returns:
-
-                FunctionNode: A FunctionNode object representing the function declaration
-
-        Raises:
-
-            SyntaxError: If the current token is not a valid function declaration
+            members.append(VariableNode(vtype, var_name, semantic))
+        self.eat("RBRACE")
+        return StructNode(name, members)
 
-        """
-        return_type = self.parse_type()
-        if self.current_token[0] == "MAIN":
-            fname = self.current_token[1]
-            self.eat("MAIN")
-        elif self.current_token[0] == "IDENTIFIER":
-            fname = self.current_token[1]
-            self.eat("IDENTIFIER")
-        else:
-            raise SyntaxError(
-                f"Expected MAIN or IDENTIFIER, got {self.current_token[0]}"
-            )
+    def parse_function(self, qualifier=None):
+        return_type = self.current_token[1]
+        self.eat(self.current_token[0])
+        name = self.current_token[1]
+        self.eat("IDENTIFIER")
         self.eat("LPAREN")
         params = self.parse_parameters()
         self.eat("RPAREN")
+        semantic = None
+        if self.current_token[0] == "AT":
+            self.eat("AT")
+            semantic = self.current_token[1]
+            self.eat("IDENTIFIER")
         self.eat("LBRACE")
         body = self.parse_body()
         self.eat("RBRACE")
-        return FunctionNode(return_type, fname, params, body)
-
-    def parse_parameters(self):
-        """Parse function parameters
-
-        This method parses function parameters in the shader code.
-
-        Returns:
-
-            list: A list of function parameters
+        return FunctionNode(return_type, name, params, body, qualifier, semantic)
 
-        """
+    def parse_main_function(self):
+        qualifier = self.current_token[1]
+        self.eat(self.current_token[0])
+        self.eat("LBRACE")
+        return self.parse_function(qualifier)
 
+    def parse_parameters(self):
         params = []
-        if self.current_token[0] != "RPAREN":
-            params.append(self.parse_parameter())
-            while self.current_token[0] == "COMMA":
-                self.eat("COMMA")
-                params.append(self.parse_parameter())
-        return params
-
-    def parse_parameter(self):
-        """Parse a function parameter
-
-        This method parses a function parameter in the shader code.
-
-        Returns:
-
-            tuple: A tuple containing the parameter type and name
-
-        """
-        param_type = self.parse_type()
-        param_name = self.current_token[1]
-
-        self.eat("IDENTIFIER")
-        return (param_type, param_name)
-
-    def parse_type(self):
-        """Parse a type declaration
-
-        This method parses a type declaration in the shader code.
-
-        Returns:
-
-            str: The type name
-
-        Raises:
-
-            SyntaxError: If the current token is not a valid type declaration
-
-        """
-        if self.current_token[0] == "VOID":
-            self.eat("VOID")
-            return "void"
-        elif self.current_token[0] in [
-            "VECTOR",
-            "FLOAT",
-            "DOUBLE",
-            "UINT",
-            "INT",
-            "MATRIX",
-            "SAMPLER2D",
-        ]:
+        while self.current_token[0] != "RPAREN":
             vtype = self.current_token[1]
             self.eat(self.current_token[0])
-            return vtype
-        elif self.current_token[0] == "IDENTIFIER":
-            type_name = self.current_token[1]
+            name = self.current_token[1]
             self.eat("IDENTIFIER")
-            if type_name in ["int", "uint", "float", "double"]:
-                return type_name
-            return type_name
-        else:
-            raise SyntaxError(f"Expected type, got {self.current_token[0]}")
+            semantic = None
+            if self.current_token[0] == "COLON":
+                self.eat("COLON")
+                semantic = self.current_token[1]
+                self.eat("IDENTIFIER")
+            params.append(VariableNode(vtype, name, semantic))
+            if self.current_token[0] == "COMMA":
+                self.eat("COMMA")
+        return params
 
     def parse_body(self):
         """Parse a function body
@@ -645,7 +439,8 @@ class Parser:
             "BITWISE_SHIFT_RIGHT",
             "BITWISE_SHIFT_LEFT",
             "BITWISE_XOR",
-            "ASSIGN_SHIFT_LEFT" "ASSIGN_SHIFT_RIGHT",
+            "ASSIGN_SHIFT_LEFT",
+            "ASSIGN_SHIFT_RIGHT",
         ]:
             return self.parse_assignment(name)
         elif self.current_token[0] == "INCREMENT":
@@ -685,6 +480,11 @@ class Parser:
         self.eat("IDENTIFIER")
         if self.current_token[0] == "DOT":
             name = self.parse_member_access(name)
+        if self.current_token[0] == "IDENTIFIER":
+            value = self.current_token[1]
+            self.eat("IDENTIFIER")
+            self.eat("SEMICOLON")
+            return VariableNode(name, value)
         if self.current_token[0] == "SEMICOLON":
             self.eat("SEMICOLON")
             return VariableNode(type_name, name)
@@ -717,7 +517,6 @@ class Parser:
             if self.current_token[0] == "SEMICOLON":
                 self.eat("SEMICOLON")
                 return BinaryOpNode(VariableNode(type_name, name), op, value)
-
             else:
                 if update_condition:
                     return BinaryOpNode(VariableNode(type_name, name), op, value)
@@ -825,7 +624,7 @@ class Parser:
                 ASTNode: An ASTNode object representing the additive expression
 
         """
-        expr = self.parse_multiplicative()
+        expr = self.parse_bitwise()
         while self.current_token[0] in ["PLUS", "MINUS"]:
             op = self.current_token[0]
             self.eat(op)
@@ -851,6 +650,30 @@ class Parser:
             expr = BinaryOpNode(expr, op, right)
         return expr
 
+    def parse_bitwise(self):
+        """Parse a bitwise expression
+
+        This method parses a bitwise expression in the shader code.
+
+        Returns:
+
+            ASTNode: An ASTNode object representing the bitwise expression
+
+        """
+        expr = self.parse_multiplicative()
+        while self.current_token[0] in [
+            "BITWISE_SHIFT_RIGHT",
+            "BITWISE_SHIFT_LEFT",
+            "BITWISE_XOR",
+            "BITWISE_AND",
+            "BITWISE_OR",
+        ]:
+            op = self.current_token[0]
+            self.eat(op)
+            right = self.parse_multiplicative()
+            expr = BinaryOpNode(expr, op, right)
+        return expr
+
     def parse_unary(self):
         """Parse a unary expression
 
diff --git a/output.slang b/output.slang
deleted file mode 100644
index 5849573..0000000
--- a/output.slang
+++ /dev/null
@@ -1,66 +0,0 @@
-// shaders.slang
-
-//
-// This file provides a simple vertex and fragment shader that can be compiled
-// using Slang. This code should also be valid as HLSL, and thus it does not
-// use any of the new language features supported by Slang.
-//
-
-// Uniform data to be passed from application -> shader.
-cbuffer Uniforms
-{
-    float4x4 modelViewProjection;
-}
-
-// Per-vertex attributes to be assembled from bound vertex buffers.
-struct AssembledVertex
-{
-    float3	position : POSITION;
-    float3	color    : COLOR;
-};
-
-// Output of the vertex shader, and input to the fragment shader.
-struct CoarseVertex
-{
-    float3 color;
-};
-
-// Output of the fragment shader
-struct Fragment
-{
-    float4 color;
-};
-
-// Vertex  Shader
-
-struct VertexStageOutput
-{
-    CoarseVertex    coarseVertex    : CoarseVertex;
-    float4          sv_position     : SV_Position;
-};
-
-[shader("vertex")]
-VertexStageOutput vertexMain(
-    AssembledVertex assembledVertex)
-{
-    VertexStageOutput output;
-
-    float3 position = assembledVertex.position;
-    float3 color    = assembledVertex.color;
-
-    output.coarseVertex.color = color;
-    output.sv_position = mul(modelViewProjection, float4(position, 1.0));
-
-    return output;
-}
-
-// Fragment Shader
-
-[shader("fragment")]
-float4 fragmentMain(
-    CoarseVertex coarseVertex : CoarseVertex) : SV_Target
-{
-    float3 color = coarseVertex.color;
-
-    return float4(color, 1.0);
-}
\ No newline at end of file
diff --git a/setup.py b/setup.py
index 477a257..ef90fec 100644
--- a/setup.py
+++ b/setup.py
@@ -21,7 +21,7 @@ setup(
     author="CrossGL team",
     author_email="vaatsalya@crossgl.net",
     description="CrossGL: Revolutionizing Shader Development",
-    long_description=open("README.md").read(),
+    long_description=open("README.md", "r", -1, "UTF8").read(),
     long_description_content_type="text/markdown",
     url="https://crossgl.net/",
     project_urls={"Documentation": "https://crossgl.github.io/index.html"},


Test patch:
diff --git a/.github/workflows/backend-tests.yml b/.github/workflows/backend-tests.yml
index f67ad70..dcc94f3 100644
--- a/.github/workflows/backend-tests.yml
+++ b/.github/workflows/backend-tests.yml
@@ -10,11 +10,13 @@ on:
 
 jobs:
   test:
-    runs-on: ubuntu-latest
+    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']
+        OS: [ubuntu-latest, windows-latest, macOS-latest]
+      fail-fast: false
 
     steps:
     - name: Checkout repository
diff --git a/.github/workflows/translator-tests.yml b/.github/workflows/translator-tests.yml
index 06abd02..36ccd23 100644
--- a/.github/workflows/translator-tests.yml
+++ b/.github/workflows/translator-tests.yml
@@ -10,11 +10,13 @@ on:
 
 jobs:
   test:
-    runs-on: ubuntu-latest
+    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']
+        OS: [ubuntu-latest, windows-latest, macOS-latest]
+      fail-fast: false
 
     steps:
     - name: Checkout repository
@@ -32,6 +34,7 @@ jobs:
         pip install -r requirements.txt
 
     - name: Run translator tests
+      shell: bash
       run: |
         if [ "${{ matrix.component }}" == "general" ]; then
           pytest tests/test_translator/test_lexer.py tests/test_translator/test_parser.py
diff --git a/tests/test_backend/test_opengl/test_codegen.py b/tests/test_backend/test_opengl/test_codegen.py
index 7efb609..bd29a70 100644
--- a/tests/test_backend/test_opengl/test_codegen.py
+++ b/tests/test_backend/test_opengl/test_codegen.py
@@ -19,7 +19,7 @@ def tokenize_code(code: str) -> List:
     return lexer.tokens
 
 
-def parse_code(Tokens: List, shader_type: str) -> List:
+def parse_code(Tokens: List, shader_type="vertex") -> List:
     """Helper function to parse code.
 
     Args:
@@ -33,7 +33,7 @@ def parse_code(Tokens: List, shader_type: str) -> List:
     return parser.parse()
 
 
-def generate_code(ast: List, shader_type: str) -> str:
+def generate_code(ast: List, shader_type="vertex") -> str:
     """Helper function to generate code.
 
     Args:
@@ -77,31 +77,32 @@ def test_input_output():
 def test_if_statement():
     code = """
     #version 450
-    // Vertex shader
+    // Fragment shader
+    layout(location = 0) in vec3 position;
+    out vec2 vUV;
+
     float perlinNoise(vec2 p) {
         return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453);
     }
 
-    in vec2 vUV;
-    layout(location = 0) out vec4 fragColor;
-
     void main() {
         float noise = perlinNoise(vUV);
-        if (noise > 0.75) {
-            fragColor = vec4(1.0, 0.0, 0.0, 1.0);
-        }
-        else if (noise > 0.5) {
-            fragColor = vec4(0.0, 1.0, 0.0, 1.0);
-        }
-        else {
-            fragColor = vec4(0.0, 0.0, 1.0, 1.0);
+        if (noise > 0.5) {
+            float fragColor = vec4(1.0, 1.0, 1.0, 1.0);
         }
     }
+
+    layout(location = 0) in vec2 vUV;
+    out vec2 color;
+
+    void main() {
+        color = position.xy * 10.0;
+    }
     """
     try:
         tokens = tokenize_code(code)
-        ast = parse_code(tokens, "fragment")
-        code = generate_code(ast, "fragment")
+        ast = parse_code(tokens)
+        code = generate_code(ast)
         print(code)
     except SyntaxError:
         pytest.fail("Struct parsing not implemented.")
diff --git a/tests/test_backend/test_opengl/test_parser.py b/tests/test_backend/test_opengl/test_parser.py
index 06f9fac..58aaa04 100644
--- a/tests/test_backend/test_opengl/test_parser.py
+++ b/tests/test_backend/test_opengl/test_parser.py
@@ -18,7 +18,7 @@ def tokenize_code(code: str) -> List:
     return lexer.tokens
 
 
-def parse_code(Tokens: List, shader_type: str) -> List:
+def parse_code(Tokens: List, shader_type="vertex") -> List:
     """Helper function to parse code.
 
     Args:
@@ -59,10 +59,22 @@ def test_if_statement():
             float fragColor = vec4(1.0, 1.0, 1.0, 1.0);
         }
     }
+
+    float perlinNoise(vec2 p) {
+        return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453);
+    }
+
+    layout(location = 0) in vec3 position;
+    out vec2 vUV;
+
+    void main() {
+        vUV = position.xy * 10.0;
+    }
+    
     """
     try:
         tokens = tokenize_code(code)
-        parse_code(tokens, "fragment")
+        print(parse_code(tokens))
     except SyntaxError:
         pytest.fail("Struct parsing not implemented.")
 
@@ -86,7 +98,7 @@ def test_for_statement():
     """
     try:
         tokens = tokenize_code(code)
-        parse_code(tokens, "vertex")
+        print(parse_code(tokens, "vertex"))
     except SyntaxError:
         pytest.fail("Struct parsing not implemented.")
 
diff --git a/tests/test_translator/test_codegen/test_directx_codegen.py b/tests/test_translator/test_codegen/test_directx_codegen.py
index 0e4160a..50e8a12 100644
--- a/tests/test_translator/test_codegen/test_directx_codegen.py
+++ b/tests/test_translator/test_codegen/test_directx_codegen.py
@@ -34,29 +34,15 @@ def generate_code(ast_node):
     return codegen.generate(ast_node)
 
 
-def test_input_output():
+def test_struct():
     code = """
-    shader PerlinNoise {
-    vertex {
-        input vec3 position;
-        output vec2 vUV;
-
-        void main() {
-            vUV = position.xy * 10.0;
-            gl_Position = vec4(position, 1.0);
-        }
-    }
+    struct VSInput {
+        vec2 texCoord @ TEXCOORD0;
+    };
 
-    // Fragment Shader
-    fragment {
-        input vec2 vUV;
-        output vec4 fragColor;
-
-        void main() {
-            fragColor = vec4(color, 1.0);
-            }
-        }
-    }
+    struct VSOutput {
+        vec4 color @ COLOR;
+    };
     """
     try:
         tokens = tokenize_code(code)
@@ -64,39 +50,59 @@ def test_input_output():
         code = generate_code(ast)
         print(code)
     except SyntaxError:
-        pytest.fail("Struct parsing not implemented.")
+        pytest.fail("Struct codegen not implemented.")
 
 
 def test_if_statement():
     code = """
-    shader PerlinNoise {
+    shader main {
+
+    struct VSInput {
+        vec2 texCoord @ TEXCOORD0;
+    };
+
+    struct VSOutput {
+        vec4 color @ COLOR;
+    };
+
+    sampler2D iChannel0;
+
     vertex {
-        input vec3 position;
-        output vec2 vUV;
+        VSOutput main(VSInput input) {
+            VSOutput output;
 
-        void main() {
-            vUV = position.xy * 10.0;
-            if (vUV.x > 0.5) {
-                vUV.x = 0.5;
+            if (input.texCoord.x > 0.5) {
+                output.color = vec4(1.0, 1.0, 1.0, 1.0);
+            } else {
+                output.color = vec4(0.0, 0.0, 0.0, 1.0);
             }
 
-            gl_Position = vec4(position, 1.0);
+            // Pass through texture coordinates as color
+            output.color = vec4(input.texCoord, 0.0, 1.0);
+
+            return output;
         }
     }
 
-    // Fragment Shader
     fragment {
-        input vec2 vUV;
-        output vec4 fragColor;
-
-        void main() {
-                if (vUV.x > 0.5) {
-                fragColor = vec4(1.0, 1.0, 1.0, 1.0);
-                }
-            fragColor = vec4(color, 1.0);
+        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);
+            if (bloom > 0.5) {
+                bloom = 0.5;
+            } else {
+                bloom = 0.0;
             }
+
+            // Apply bloom to the texture color
+            vec3 texColor = texture(iChannel0, input.color.xy).rgb;
+            vec3 colorWithBloom = texColor + vec3(bloom);
+
+            return vec4(colorWithBloom, 1.0);
         }
     }
+}
     """
     try:
         tokens = tokenize_code(code)
@@ -104,81 +110,37 @@ def test_if_statement():
         code = generate_code(ast)
         print(code)
     except SyntaxError:
-        pytest.fail("Struct parsing not implemented.")
+        pytest.fail("if statement codegen not implemented.")
 
 
 def test_for_statement():
     code = """
-    shader PerlinNoise {
-    vertex {
-        input vec3 position;
-        output vec2 vUV;
+    shader main {
 
-        void main() {
-            vUV = position.xy * 10.0;
-            for (int i = 0; i < 10; i = i + 1) {
-                vUV = vec2(0.0, 0.0);
-            }
-            gl_Position = vec4(position, 1.0);
-        }
-    }
+    struct VSInput {
+        vec2 texCoord @ TEXCOORD0;
+    };
 
-    // Fragment Shader
-    fragment {
-        input vec2 vUV;
-        output vec4 fragColor;
-
-        void main() {
-            for (int i = 0; i < 10; i = i + 1) {
-                vec3 color = vec3(1.0, 1.0, 1.0);
-            }
-            fragColor = vec4(color, 1.0);
-            }
-        }
-    }
-    """
-    try:
-        tokens = tokenize_code(code)
-        ast = parse_code(tokens)
-        code = generate_code(ast)
-        print(code)
-    except SyntaxError:
-        pytest.fail("Struct parsing not implemented.")
+    struct VSOutput {
+        vec4 color @ COLOR;
+    };
 
+    sampler2D iChannel0;
 
-def test_else_statement():
-    code = """
-    shader PerlinNoise {
     vertex {
-        input vec3 position;
-        output vec2 vUV;
+        VSOutput main(VSInput input) {
+            VSOutput output;
 
-        void main() {
-            vUV = position.xy * 10.0;
-            if (vUV.x > 0.5) {
-                vUV.x = 0.5;
-            } else {
-                vUV.x = 0.0;
+            for (int i = 0; i < 10; i++) {
+                output.color = vec4(1.0, 1.0, 1.0, 1.0);
             }
-            gl_Position = vec4(position, 1.0);
-        }
-    }
+            // Pass through texture coordinates as color
+            output.color = vec4(input.texCoord, 0.0, 1.0);
 
-    // Fragment Shader
-    fragment {
-        input vec2 vUV;
-        output vec4 fragColor;
-
-        void main() {
-            if (vUV.x > 0.5) {
-            fragColor = vec4(1.0, 1.0, 1.0, 1.0);
-            } else {
-                fragColor = vec4(0.0, 0.0, 0.0, 1.0);
-            }
-            fragColor = vec4(color, 1.0);
-            }
+            return output;
         }
     }
+}
     """
     try:
         tokens = tokenize_code(code)
@@ -186,51 +148,63 @@ def test_else_statement():
         code = generate_code(ast)
         print(code)
     except SyntaxError:
-        pytest.fail("Struct parsing not implemented.")
+        pytest.fail("for statement codegen not implemented.")
 
 
 def test_else_if_statement():
     code = """
-    shader PerlinNoise {
+    shader main {
+
+    struct VSInput {
+        vec2 texCoord @ TEXCOORD0;
+    };
+
+    struct VSOutput {
+        vec4 color @ COLOR;
+    };
+
+    sampler2D iChannel0;
+
     vertex {
-        input vec3 position;
-        output vec2 vUV;
+        VSOutput main(VSInput input) {
+            VSOutput output;
 
-        void main() {
-            vUV = position.xy * 10.0;
-            if (vUV.x < 0.5) {
-                vUV.x = 0.25;
-            }
-            if (vUV.x < 0.25) {
-                vUV.x = 0.0;
-            } else if (vUV.x < 0.75) {
-                vUV.x = 0.5;
-            } else if (vUV.x < 1.0) {
-                vUV.x = 0.75;
+            if (input.texCoord.x > 0.5) {
+                output.color = vec4(1.0, 1.0, 1.0, 1.0);
+            } else if (input.texCoord.x < 0.5) {
+                output.color = vec4(0.0, 0.0, 0.0, 1.0);
             } else {
-                vUV.x = 0.0;
-            }
-            gl_Position = vec4(position, 1.0);
+                output.color = vec4(0.5, 0.5, 0.5, 1.0);
+
+            // Pass through texture coordinates as color
+            output.color = vec4(input.texCoord, 0.0, 1.0);
+
+            return output;
         }
     }
-
-    // Fragment Shader
-    fragment {
-        input vec2 vUV;
-        output vec4 fragColor;
-
-        void main() {
-            if (vUV.x > 0.75) {
-                fragColor = vec4(1.0, 1.0, 1.0, 1.0);
-            } else if (vUV.x > 0.5) {
-                fragColor = vec4(0.5, 0.5, 0.5, 1.0);
+}
+
+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);
+            if (bloom > 0.5) {
+                bloom = 0.5;
+            } else if (bloom < 0.5) {
+                bloom = 0.0;
             } else {
-                fragColor = vec4(0.0, 0.0, 0.0, 1.0);
-            }
-            fragColor = vec4(color, 1.0);
+                bloom = 0.5;
             }
+            // Apply bloom to the texture color
+            vec3 texColor = texture(iChannel0, input.color.xy).rgb;
+            vec3 colorWithBloom = texColor + vec3(bloom);
+
+            return vec4(colorWithBloom, 1.0);
         }
     }
+}
+
     """
     try:
         tokens = tokenize_code(code)
@@ -238,40 +212,49 @@ def test_else_if_statement():
         code = generate_code(ast)
         print(code)
     except SyntaxError:
-        pytest.fail("Struct parsing not implemented.")
+        pytest.fail("else if codegen not implemented.")
 
 
 def test_function_call():
     code = """
-    shader PerlinNoise {
-    vertex {
-        input vec3 position;
-        output vec2 vUV;
+    shader main {
 
-        void main() {
-            vUV = position.xy * 10.0;
-            gl_Position = vec4(position, 1.0);
-        }
+    struct VSInput {
+        vec2 texCoord @ TEXCOORD0;
+    };
+
+    struct VSOutput {
+        vec4 color @ COLOR;
+    };
+
+    sampler2D iChannel0;
+
+    vec4 addColor(vec4 color1, vec4 color2) {
+        return color1 + color2;
     }
 
-    // Perlin Noise Function
-    float perlinNoise(vec2 p) {
-        return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453);
+    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));
+            // Pass through texture coordinates as color
+            output.color = vec4(input.texCoord, 0.0, 1.0);
+            return output;
+        }
     }
 
-    // Fragment Shader
     fragment {
-        input vec2 vUV;
-        output vec4 fragColor;
-
-        void main() {
-            float noise = perlinNoise(vUV);
-            float height = noise * 10.0;
-            vec3 color = vec3(height / 10.0, 1.0 - height / 10.0, 0.0);
-            fragColor = vec4(color, 1.0);
-            }
+        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
+            vec3 texColor = texture(iChannel0, input.color.xy).rgb;
+            vec3 colorWithBloom = texColor + vec3(bloom);
+            return vec4(colorWithBloom, 1.0);
         }
     }
+}
 
     """
     try:
@@ -280,68 +263,95 @@ def test_function_call():
         code = generate_code(ast)
         print(code)
     except SyntaxError:
-        pytest.fail("Struct parsing not implemented.")
+        pytest.fail("function call codegen not implemented.")
 
 
 def test_assignment_or_operator():
     code = """
-    shader ORShader {
-        vertex {
-            input vec3 position;
-            output vec2 vUV;
-            void main() {
-                vUV = position.xy * 10.0;
-                vUV.x |= 3.0;  // OR assignment operator
-                gl_Position = vec4(position, 1.0);
-            }
+    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));
+            vUV.x |= 3.0;  // OR assignment operator
+            // Pass through texture coordinates as color
+            output.color = vec4(input.texCoord, 0.0, 1.0);
+            return output;
         }
-        fragment {
-            input vec2 vUV;
-            output vec4 fragColor;
-            void main() {
-                float noise = perlinNoise(vUV);
-                float height = noise * 10.0;
-                height |= 2.0;  // OR assignment operator
-                vec3 color = vec3(height / 10.0, 1.0 - height / 10.0, 0.0);
-                fragColor = vec4(color, 1.0);
-            }
+    }
+
+    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
+            vUV.x |= 3.0;  // OR assignment operator
+            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("OR operator parsing not implemented.")
+        pytest.fail("OR operator codegen not implemented.")
 
 
 def test_assignment_modulus_operator():
     code = """
-    shader ModulusShader {
+    shader main {
+
+    struct VSInput {
+        vec2 texCoord @ TEXCOORD0;
+    };
+
+    struct VSOutput {
+        vec4 color @ COLOR;
+    };
+
+    sampler2D iChannel0;
+
     vertex {
-        input vec3 position;
-        output vec2 vUV;
-        void main() {
-            vUV = position.xy * 10.0;
-            vUV.x %= 3.0;  // Modulus assignment operator
-            gl_Position = vec4(position, 1.0);
+        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 %= b;
+            // Pass through texture coordinates as color
+            output.color = vec4(input.texCoord, 0.0, 1.0);
+            return output;
         }
     }
-    // Fragment Shader
+
     fragment {
-        input vec2 vUV;
-        output vec4 fragColor;
-     void main() {
-            float noise = perlinNoise(vUV);
-            float height = noise * 10.0;
-            height %= 2.0;  // Modulus assignment operator
-             vec3 color = vec3(height / 10.0, 1.0 - height / 10.0, 0.0);
-            fragColor = vec4(color, 1.0);
-            }
+        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 %= b;
+            vec3 texColor = texture(iChannel0, input.color.xy).rgb;
+            vec3 colorWithBloom = texColor + vec3(bloom);
+            return vec4(colorWithBloom, 1.0);
         }
     }
+}
     """
     try:
         tokens = tokenize_code(code)
@@ -349,33 +359,47 @@ def test_assignment_modulus_operator():
         code = generate_code(ast)
         print(code)
     except SyntaxError:
-        pytest.fail("Struct parsing not implemented.")
+        pytest.fail("assignment modulus codegen not implemented.")
 
 
 def test_assignment_xor_operator():
     code = """
-    shader XORShader {
-        vertex {
-            input vec3 position;
-            output vec2 vUV;
-            void main() {
-                vUV = position.xy * 10.0;
-                vUV.x ^= 3.0;  // XOR assignment operator
-                gl_Position = vec4(position, 1.0);
-            }
+    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 ^= b;
+            // Pass through texture coordinates as color
+            output.color = vec4(input.texCoord, 0.0, 1.0);
+            return output;
         }
-        fragment {
-            input vec2 vUV;
-            output vec4 fragColor;
-            void main() {
-                float noise = perlinNoise(vUV);
-                float height = noise * 10.0;
-                height ^= 2.0;  // XOR assignment operator
-                vec3 color = vec3(height / 10.0, 1.0 - height / 10.0, 0.0);
-                fragColor = vec4(color, 1.0);
-            }
+    }
+
+    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 ^= b;
+            vec3 texColor = texture(iChannel0, input.color.xy).rgb;
+            vec3 colorWithBloom = texColor + vec3(bloom);
+            return vec4(colorWithBloom, 1.0);
         }
     }
+}
     """
     try:
         tokens = tokenize_code(code)
@@ -383,34 +407,49 @@ def test_assignment_xor_operator():
         generated_code = generate_code(ast)
         print(generated_code)
     except SyntaxError:
-        pytest.fail("XOR operator parsing not implemented.")
+        pytest.fail("XOR operator codegen not implemented.")
 
 
 def test_assignment_shift_operators():
     code = """
-    shader PerlinNoise {
-    vertex {
-        input vec3 position;
-        output vec2 vUV;
+    shader main {
+
+    struct VSInput {
+        vec2 texCoord @ TEXCOORD0;
+    };
+
+    struct VSOutput {
+        vec4 color @ COLOR;
+    };
 
-        void main() {
-            vUV = position.xy * 10.0;
-            vUV.x <<= 1;
-            gl_Position = vec4(position, 1.0);
+    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;
+            uint b <<= 2;
+            // Pass through texture coordinates as color
+            output.color = vec4(input.texCoord, 0.0, 1.0);
+            return output;
         }
     }
-    // Fragment Shader
+
     fragment {
-        input vec2 vUV;
-        output vec4 fragColor;
-        void main() {
-            float noise = perlinNoise(vUV);
-            float height <<= noise * 10.0;
-            vec3 color = vec3(height / 10.0, 1.0 - height / 10.0, 0.0);
-            fragColor = vec4(color, 1.0);
-            }
+        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;
+            uint b <<= 2;
+            vec3 texColor = texture(iChannel0, input.color.xy).rgb;
+            vec3 colorWithBloom = texColor + vec3(bloom);
+            return vec4(colorWithBloom, 1.0);
         }
     }
+}
     """
     try:
         tokens = tokenize_code(code)
@@ -418,36 +457,55 @@ def test_assignment_shift_operators():
         code = generate_code(ast)
         print(code)
     except SyntaxError:
-        pytest.fail("Assignment shift parsing not implemented.")
+        pytest.fail("Assignment shift codegen not implemented.")
 
 
 def test_bitwise_operators():
     code = """
-        shader LightControl {
-        vertex {
-            input vec3 position;
-            output int isLightOn;
-            void main() {        
-                    isLightOn = 2 >> 1;
-            }
-        }
-        fragment {
-            input int isLightOn;
-            output vec4 fragColor;
-            void main() {
-                isLightOn = isLightOn << 1;
-            }
+    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));
+            isLightOn = 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
+            isLightOn = 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)
         code = generate_code(ast)
         print(code)
     except SyntaxError:
-        pytest.fail("Bitwise Shift parsing not implemented.")
+        pytest.fail("Bitwise Shift codegen not implemented")
 
 
 if __name__ == "__main__":
diff --git a/tests/test_translator/test_codegen/test_metal_codegen.py b/tests/test_translator/test_codegen/test_metal_codegen.py
index 9585b2d..b6a5cfd 100644
--- a/tests/test_translator/test_codegen/test_metal_codegen.py
+++ b/tests/test_translator/test_codegen/test_metal_codegen.py
@@ -34,29 +34,16 @@ def generate_code(ast_node):
     return codegen.generate(ast_node)
 
 
-def test_input_output():
+def test_struct():
     code = """
-    shader PerlinNoise {
-    vertex {
-        input vec3 position;
-        output vec2 vUV;
-
-        void main() {
-            vUV = position.xy * 10.0;
-            gl_Position = vec4(position, 1.0);
-        }
-    }
+    struct VSInput {
+        vec2 texCoord @ TEXCOORD0;
+    };
 
-    // Fragment Shader
-    fragment {
-        input vec2 vUV;
-        output vec4 fragColor;
+    struct VSOutput {
+        vec4 color @ COLOR;
+    };
 
-        void main() {
-            fragColor = vec4(color, 1.0);
-            }
-        }
-    }
     """
     try:
         tokens = tokenize_code(code)
@@ -64,39 +51,59 @@ def test_input_output():
         code = generate_code(ast)
         print(code)
     except SyntaxError:
-        pytest.fail("Struct parsing not implemented.")
+        pytest.fail("Struct codegen not implemented.")
 
 
 def test_if_statement():
     code = """
-    shader PerlinNoise {
+    shader main {
+
+    struct VSInput {
+        vec2 texCoord @ TEXCOORD0;
+    };
+
+    struct VSOutput {
+        vec4 color @ COLOR;
+    };
+
+    sampler2D iChannel0;
+
     vertex {
-        input vec3 position;
-        output vec2 vUV;
+        VSOutput main(VSInput input) {
+            VSOutput output;
 
-        void main() {
-            vUV = position.xy * 10.0;
-            if (vUV.x > 0.5) {
-                vUV.x = 0.5;
+            if (input.texCoord.x > 0.5) {
+                output.color = vec4(1.0, 1.0, 1.0, 1.0);
+            } else {
+                output.color = vec4(0.0, 0.0, 0.0, 1.0);
             }
 
-            gl_Position = vec4(position, 1.0);
+            // Pass through texture coordinates as color
+            output.color = vec4(input.texCoord, 0.0, 1.0);
+
+            return output;
         }
     }
 
-    // Fragment Shader
     fragment {
-        input vec2 vUV;
-        output vec4 fragColor;
-
-        void main() {
-                if (vUV.x > 0.5) {
-                fragColor = vec4(1.0, 1.0, 1.0, 1.0);
-                }
-            fragColor = vec4(color, 1.0);
+        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);
+            if (bloom > 0.5) {
+                bloom = 0.5;
+            } else {
+                bloom = 0.0;
             }
+
+            // Apply bloom to the texture color
+            vec3 texColor = texture(iChannel0, input.color.xy).rgb;
+            vec3 colorWithBloom = texColor + vec3(bloom);
+
+            return vec4(colorWithBloom, 1.0);
         }
     }
+
     """
     try:
         tokens = tokenize_code(code)
@@ -104,81 +111,36 @@ def test_if_statement():
         code = generate_code(ast)
         print(code)
     except SyntaxError:
-        pytest.fail("Struct parsing not implemented.")
+        pytest.fail("if statement codegen not implemented.")
 
 
 def test_for_statement():
     code = """
-    shader PerlinNoise {
-    vertex {
-        input vec3 position;
-        output vec2 vUV;
+    shader main {
+    struct VSInput {
+        vec2 texCoord @ TEXCOORD0;
+    };
 
-        void main() {
-            vUV = position.xy * 10.0;
-            for (int i = 0; i < 10; i = i + 1) {
-                vUV = vec2(0.0, 0.0);
-            }
-            gl_Position = vec4(position, 1.0);
-        }
-    }
-
-    // Fragment Shader
-    fragment {
-        input vec2 vUV;
-        output vec4 fragColor;
-
-        void main() {
-            for (int i = 0; i < 10; i = i + 1) {
-                vec3 color = vec3(1.0, 1.0, 1.0);
-            }
-            fragColor = vec4(color, 1.0);
-            }
-        }
-    }
-    """
-    try:
-        tokens = tokenize_code(code)
-        ast = parse_code(tokens)
-        code = generate_code(ast)
-        print(code)
-    except SyntaxError:
-        pytest.fail("Struct parsing not implemented.")
+    struct VSOutput {
+        vec4 color @ COLOR;
+    };
 
+    sampler2D iChannel0;
 
-def test_else_statement():
-    code = """
-    shader PerlinNoise {
     vertex {
-        input vec3 position;
-        output vec2 vUV;
+        VSOutput main(VSInput input) {
+            VSOutput output;
 
-        void main() {
-            vUV = position.xy * 10.0;
-            if (vUV.x > 0.5) {
-                vUV.x = 0.5;
-            } else {
-                vUV.x = 0.0;
+            for (int i = 0; i < 10; i++) {
+                output.color = vec4(1.0, 1.0, 1.0, 1.0);
             }
-            gl_Position = vec4(position, 1.0);
-        }
-    }
-
-    // Fragment Shader
-    fragment {
-        input vec2 vUV;
-        output vec4 fragColor;
+            // Pass through texture coordinates as color
+            output.color = vec4(input.texCoord, 0.0, 1.0);
 
-        void main() {
-            if (vUV.x > 0.5) {
-            fragColor = vec4(1.0, 1.0, 1.0, 1.0);
-            } else {
-                fragColor = vec4(0.0, 0.0, 0.0, 1.0);
-            }
-            fragColor = vec4(color, 1.0);
-            }
+            return output;
         }
     }
+}
     """
     try:
         tokens = tokenize_code(code)
@@ -186,53 +148,63 @@ def test_else_statement():
         code = generate_code(ast)
         print(code)
     except SyntaxError:
-        pytest.fail("Struct parsing not implemented.")
+        pytest.fail("for statement codegen not implemented.")
 
 
 def test_else_if_statement():
     code = """
-    shader PerlinNoise {
+    shader main {
+
+    struct VSInput {
+        vec2 texCoord @ TEXCOORD0;
+    };
+
+    struct VSOutput {
+        vec4 color @ COLOR;
+    };
+
+    sampler2D iChannel0;
+
     vertex {
-        input vec3 position;
-        output vec2 vUV;
+        VSOutput main(VSInput input) {
+            VSOutput output;
 
-        void main() {
-            vUV = position.xy * 10.0;
-            if (vUV.x < 0.5) {
-                vUV.x = 0.25;
-            }
-            if (vUV.x < 0.25) {
-                vUV.x = 0.0;
-            } else if (vUV.x < 0.75) {
-                vUV.x = 0.5;
-            } else if (vUV.x < 1.0) {
-                vUV.x = 0.75;
+            if (input.texCoord.x > 0.5) {
+                output.color = vec4(1.0, 1.0, 1.0, 1.0);
+            } else if (input.texCoord.x < 0.5) {
+                output.color = vec4(0.0, 0.0, 0.0, 1.0);
             } else {
-                vUV.x = 0.0;
-            }
-            gl_Position = vec4(position, 1.0);
+                output.color = vec4(0.5, 0.5, 0.5, 1.0);
+
+            // Pass through texture coordinates as color
+            output.color = vec4(input.texCoord, 0.0, 1.0);
+
+            return output;
         }
     }
-
-    // Fragment Shader
-    fragment {
-        input vec2 vUV;
-        output vec4 fragColor;
-
-        void main() {
-            if (vUV.x > 0.75) {
-                fragColor = vec4(1.0, 1.0, 1.0, 1.0);
-            } else if (vUV.x > 0.5) {
-                fragColor = vec4(0.5, 0.5, 0.5, 1.0);
-            } else if (vUV.x > 0.25) {
-                fragColor = vec4(0.25, 0.25, 0.25, 1.0);
+}
+
+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);
+            if (bloom > 0.5) {
+                bloom = 0.5;
+            } else if (bloom < 0.5) {
+                bloom = 0.0;
             } else {
-                fragColor = vec4(0.0, 0.0, 0.0, 1.0);
-            }
-            fragColor = vec4(color, 1.0);
+                bloom = 0.5;
             }
+            // Apply bloom to the texture color
+            vec3 texColor = texture(iChannel0, input.color.xy).rgb;
+            vec3 colorWithBloom = texColor + vec3(bloom);
+
+            return vec4(colorWithBloom, 1.0);
         }
     }
+}
+
     """
     try:
         tokens = tokenize_code(code)
@@ -240,40 +212,49 @@ def test_else_if_statement():
         code = generate_code(ast)
         print(code)
     except SyntaxError:
-        pytest.fail("Struct parsing not implemented.")
+        pytest.fail("else if codegen not implemented.")
 
 
 def test_function_call():
     code = """
-    shader PerlinNoise {
-    vertex {
-        input vec3 position;
-        output vec2 vUV;
+    shader main {
 
-        void main() {
-            vUV = position.xy * 10.0;
-            gl_Position = vec4(position, 1.0);
-        }
+    struct VSInput {
+        vec2 texCoord @ TEXCOORD0;
+    };
+
+    struct VSOutput {
+        vec4 color @ COLOR;
+    };
+
+    sampler2D iChannel0;
+
+    vec4 addColor(vec4 color1, vec4 color2) {
+        return color1 + color2;
     }
 
-    // Perlin Noise Function
-    float perlinNoise(vec2 p) {
-        return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453);
+    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));
+            // Pass through texture coordinates as color
+            output.color = vec4(input.texCoord, 0.0, 1.0);
+            return output;
+        }
     }
 
-    // Fragment Shader
     fragment {
-        input vec2 vUV;
-        output vec4 fragColor;
-
-        void main() {
-            float noise = perlinNoise(vUV);
-            float height = noise * 10.0;
-            vec3 color = vec3(height / 10.0, 1.0 - height / 10.0, 0.0);
-            fragColor = vec4(color, 1.0);
-            }
+        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
+            vec3 texColor = texture(iChannel0, input.color.xy).rgb;
+            vec3 colorWithBloom = texColor + vec3(bloom);
+            return vec4(colorWithBloom, 1.0);
         }
     }
+}
 
     """
     try:
@@ -282,36 +263,49 @@ def test_function_call():
         code = generate_code(ast)
         print(code)
     except SyntaxError:
-        pytest.fail("Struct parsing not implemented.")
+        pytest.fail("function call codegen not implemented.")
 
 
 def test_assignment_shift_operators():
     code = """
-    shader PerlinNoise {
-    vertex {
-        input vec3 position;
-        output vec2 vUV;
+    shader main {
 
-        void main() {
-            vUV = position.xy * 10.0;
-            vUV.x <<= 1;
-            gl_Position = vec4(position, 1.0);
+    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;
+            uint b <<= 2;
+            // Pass through texture coordinates as color
+            output.color = vec4(input.texCoord, 0.0, 1.0);
+            return output;
         }
     }
 
-    // Fragment Shader
     fragment {
-        input vec2 vUV;
-        output vec4 fragColor;
-
-        void main() {
-            float noise = perlinNoise(vUV);
-            float height <<= noise * 10.0;
-            vec3 color = vec3(height / 10.0, 1.0 - height / 10.0, 0.0);
-            fragColor = vec4(color, 1.0);
-            }
+        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;
+            uint b <<= 2;
+            vec3 texColor = texture(iChannel0, input.color.xy).rgb;
+            vec3 colorWithBloom = texColor + vec3(bloom);
+            return vec4(colorWithBloom, 1.0);
         }
     }
+}
 
     """
     try:
@@ -320,27 +314,47 @@ def test_assignment_shift_operators():
         code = generate_code(ast)
         print(code)
     except SyntaxError:
-        pytest.fail("Struct parsing not implemented.")
+        pytest.fail("assignment shift codegen not implemented.")
 
 
 def test_bitwise_operators():
     code = """
-        shader LightControl {
-        vertex {
-            input vec3 position;
-            output int isLightOn;
-            void main() {        
-                    isLightOn = 2 >> 1;
-            }
+    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));
+            isLightOn = 2 >> 1;
+            // Pass through texture coordinates as color
+            output.color = vec4(input.texCoord, 0.0, 1.0);
+            return output;
         }
-        fragment {
-            input int isLightOn;
-            output vec4 fragColor;
-            void main() {
-                isLightOn = isLightOn << 1;
-            }
+    }
+
+    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
+            isLightOn = 2 >> 1;
+            vec3 texColor = texture(iChannel0, input.color.xy).rgb;
+            vec3 colorWithBloom = texColor + vec3(bloom);
+            return vec4(colorWithBloom, 1.0);
         }
     }
+}
 
     """
     try:
@@ -349,7 +363,7 @@ def test_bitwise_operators():
         code = generate_code(ast)
         print(code)
     except SyntaxError:
-        pytest.fail("Bitwise Shift parsing not implemented.")
+        pytest.fail("Bitwise Shift codegen not implemented.")
 
 
 if __name__ == "__main__":
diff --git a/tests/test_translator/test_codegen/test_opengl_codegen.py b/tests/test_translator/test_codegen/test_opengl_codegen.py
index ef56b95..b52961f 100644
--- a/tests/test_translator/test_codegen/test_opengl_codegen.py
+++ b/tests/test_translator/test_codegen/test_opengl_codegen.py
@@ -36,27 +36,14 @@ def generate_code(ast_node):
 
 def test_input_output():
     code = """
-    shader PerlinNoise {
-    vertex {
-        input vec3 position;
-        output vec2 vUV;
-
-        void main() {
-            vUV = position.xy * 10.0;
-            gl_Position = vec4(position, 1.0);
-        }
-    }
+    struct VSInput {
+        vec2 texCoord @ TEXCOORD0;
+    };
 
-    // Fragment Shader
-    fragment {
-        input vec2 vUV;
-        output vec4 fragColor;
+    struct VSOutput {
+        vec4 color @ COLOR;
+    };
 
-        void main() {
-            fragColor = vec4(color, 1.0);
-            }
-        }
-    }
     """
     try:
         tokens = tokenize_code(code)
@@ -69,34 +56,54 @@ def test_input_output():
 
 def test_if_statement():
     code = """
-    shader PerlinNoise {
+    shader main {
+
+    struct VSInput {
+        vec2 texCoord @ TEXCOORD0;
+    };
+
+    struct VSOutput {
+        vec4 color @ COLOR;
+    };
+
+    sampler2D iChannel0;
+
     vertex {
-        input vec3 position;
-        output vec2 vUV;
+        VSOutput main(VSInput input) {
+            VSOutput output;
 
-        void main() {
-            vUV = position.xy * 10.0;
-            if (vUV.x > 0.5) {
-                vUV.x = 0.5;
+            if (input.texCoord.x > 0.5) {
+                output.color = vec4(1.0, 1.0, 1.0, 1.0);
+            } else {
+                output.color = vec4(0.0, 0.0, 0.0, 1.0);
             }
 
-            gl_Position = vec4(position, 1.0);
+            // Pass through texture coordinates as color
+            output.color = vec4(input.texCoord, 0.0, 1.0);
+
+            return output;
         }
     }
 
-    // Fragment Shader
     fragment {
-        input vec2 vUV;
-        output vec4 fragColor;
-
-        void main() {
-                if (vUV.x > 0.5) {
-                fragColor = vec4(1.0, 1.0, 1.0, 1.0);
-                }
-            fragColor = vec4(color, 1.0);
+        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);
+            if (bloom > 0.5) {
+                bloom = 0.5;
+            } else {
+                bloom = 0.0;
             }
+
+            // Apply bloom to the texture color
+            vec3 texColor = texture(iChannel0, input.color.xy).rgb;
+            vec3 colorWithBloom = texColor + vec3(bloom);
+
+            return vec4(colorWithBloom, 1.0);
         }
     }
+}
     """
     try:
         tokens = tokenize_code(code)
@@ -109,33 +116,52 @@ def test_if_statement():
 
 def test_for_statement():
     code = """
-    shader PerlinNoise {
-    vertex {
-        input vec3 position;
-        output vec2 vUV;
+    shader main {
+
+    struct VSInput {
+        vec2 texCoord @ TEXCOORD0;
+    };
 
-        void main() {
-            vUV = position.xy * 10.0;
-            for (int i = 0; i < 10; i = i + 1) {
-                vUV = vec2(0.0, 0.0);
+    struct VSOutput {
+        vec4 color @ COLOR;
+    };
+
+    sampler2D iChannel0;
+
+    vertex {
+        VSOutput main(VSInput input) {
+            VSOutput output;
+            for (int i = 0; i < 10; i=i+1) {
+                output.color = vec4(1.0, 1.0, 1.0, 1.0);
             }
-            gl_Position = vec4(position, 1.0);
+            // Pass through texture coordinates as color
+            output.color = vec4(input.texCoord, 0.0, 1.0);
+
+            return output;
         }
     }
 
-    // Fragment Shader
     fragment {
-        input vec2 vUV;
-        output vec4 fragColor;
-
-        void main() {
-            for (int i = 0; i < 10; i = i + 1) {
-                vec3 color = vec3(1.0, 1.0, 1.0);
-            }
-            fragColor = vec4(color, 1.0);
+        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);
+            for (int i = 0; i < 10; i++) {
+                if (i > 0.5) {
+                    bloom = 0.5;
+                } else {
+                    bloom = 0.0;
+                }
             }
+
+            // Apply bloom to the texture color
+            vec3 texColor = texture(iChannel0, input.color.xy).rgb;
+            vec3 colorWithBloom = texColor + vec3(bloom);
+
+            return vec4(colorWithBloom, 1.0);
         }
     }
+}
     """
     try:
         tokens = tokenize_code(code)
@@ -148,37 +174,54 @@ def test_for_statement():
 
 def test_else_statement():
     code = """
-    shader PerlinNoise {
+    shader main {
+
+    struct VSInput {
+        vec2 texCoord @ TEXCOORD0;
+    };
+
+    struct VSOutput {
+        vec4 color @ COLOR;
+    };
+
+    sampler2D iChannel0;
+
     vertex {
-        input vec3 position;
-        output vec2 vUV;
+        VSOutput main(VSInput input) {
+            VSOutput output;
 
-        void main() {
-            vUV = position.xy * 10.0;
-            if (vUV.x > 0.5) {
-                vUV.x = 0.5;
+            if (input.texCoord.x > 0.5) {
+                output.color = vec4(1.0, 1.0, 1.0, 1.0);
             } else {
-                vUV.x = 0.0;
+                output.color = vec4(0.0, 0.0, 0.0, 1.0);
             }
-            gl_Position = vec4(position, 1.0);
+
+            // Pass through texture coordinates as color
+            output.color = vec4(input.texCoord, 0.0, 1.0);
+
+            return output;
         }
     }
 
-    // Fragment Shader
     fragment {
-        input vec2 vUV;
-        output vec4 fragColor;
-
-        void main() {
-            if (vUV.x > 0.5) {
-            fragColor = vec4(1.0, 1.0, 1.0, 1.0);
+        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);
+            if (bloom > 0.5) {
+                bloom = 0.5;
             } else {
-                fragColor = vec4(0.0, 0.0, 0.0, 1.0);
-            }
-            fragColor = vec4(color, 1.0);
+                bloom = 0.0;
             }
+
+            // Apply bloom to the texture color
+            vec3 texColor = texture(iChannel0, input.color.xy).rgb;
+            vec3 colorWithBloom = texColor + vec3(bloom);
+
+            return vec4(colorWithBloom, 1.0);
         }
     }
+}
     """
     try:
         tokens = tokenize_code(code)
@@ -191,48 +234,59 @@ def test_else_statement():
 
 def test_else_if_statement():
     code = """
-    shader PerlinNoise {
+    shader main {
+
+    struct VSInput {
+        vec2 texCoord @ TEXCOORD0;
+    };
+
+    struct VSOutput {
+        vec4 color @ COLOR;
+    };
+
+    sampler2D iChannel0;
+
     vertex {
-        input vec3 position;
-        output vec2 vUV;
+        VSOutput main(VSInput input) {
+            VSOutput output;
 
-        void main() {
-            vUV = position.xy * 10.0;
-            if (vUV.x < 0.5) {
-                vUV.x = 0.25;
-            }
-            if (vUV.x < 0.25) {
-                vUV.x = 0.0;
-            } else if (vUV.x < 0.75) {
-                vUV.x = 0.5;
-            } else if (vUV.x < 1.0) {
-                vUV.x = 0.75;
+            if (input.texCoord.x > 0.5) {
+                output.color = vec4(1.0, 1.0, 1.0, 1.0);
+            } else if (input.texCoord.x < 0.5) {
+                output.color = vec4(0.0, 0.0, 0.0, 1.0);
             } else {
-                vUV.x = 0.0;
+                output.color = vec4(0.5, 0.5, 0.5, 1.0);
             }
-            gl_Position = vec4(position, 1.0);
+
+            // Pass through texture coordinates as color
+            output.color = vec4(input.texCoord, 0.0, 1.0);
+
+            return output;
         }
     }
 
-    // Fragment Shader
     fragment {
-        input vec2 vUV;
-        output vec4 fragColor;
-
-        void main() {
-            if (vUV.x > 0.75) {
-                fragColor = vec4(1.0, 1.0, 1.0, 1.0);
-            } else if (vUV.x > 0.5) {
-                fragColor = vec4(0.5, 0.5, 0.5, 1.0);
-            } else if (vUV.x > 0.25) {
-                fragColor = vec4(0.25, 0.25, 0.25, 1.0);
+        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);
+            if (bloom > 0.5) {
+                bloom = 0.5;
+            } else if (bloom < 0.5) {
+                bloom = 0.1;
             } else {
-                fragColor = vec4(0.0, 0.0, 0.0, 1.0);
-            }
-            fragColor = vec4(color, 1.0);
+                bloom = 0.0;
             }
+
+
+            // Apply bloom to the texture color
+            vec3 texColor = texture(iChannel0, input.color.xy).rgb;
+            vec3 colorWithBloom = texColor + vec3(bloom);
+
+            return vec4(colorWithBloom, 1.0);
         }
     }
+}
     """
     try:
         tokens = tokenize_code(code)
@@ -245,35 +299,59 @@ def test_else_if_statement():
 
 def test_function_call():
     code = """
-    shader PerlinNoise {
-    vertex {
-        input vec3 position;
-        output vec2 vUV;
+    shader perlinNoise {
 
-        void main() {
-            vUV = position.xy * 10.0;
-            gl_Position = vec4(position, 1.0);
-        }
+    struct VSInput {
+        vec2 texCoord @ TEXCOORD0;
+    };
+
+    struct VSOutput {
+        vec4 color @ COLOR;
+    };
+
+    vec2 perlinNoise(vec2 uv) {
+        return vec2(0.0, 0.0);
     }
+    
+    sampler2D iChannel0;
+
+    vertex {
+        VSOutput main(VSInput input) {
+            VSOutput output;
+            vec2 noise = perlinNoise(input.texCoord);
+            if (input.texCoord.x > 0.5) {
+                output.color = vec4(1.0, 1.0, 1.0, 1.0);
+            } else {
+                output.color = vec4(0.0, 0.0, 0.0, 1.0);
+            }
+
+            // Pass through texture coordinates as color
+            output.color = vec4(input.texCoord, 0.0, 1.0);
 
-    // Perlin Noise Function
-    float perlinNoise(vec2 p) {
-        return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453);
+            return output;
+        }
     }
 
-    // Fragment Shader
     fragment {
-        input vec2 vUV;
-        output vec4 fragColor;
-
-        void main() {
-            float noise = perlinNoise(vUV);
-            float height = noise * 10.0;
-            vec3 color = vec3(height / 10.0, 1.0 - height / 10.0, 0.0);
-            fragColor = vec4(color, 1.0);
+        vec4 main(VSOutput input) @ gl_FragColor {
+            vec2 noise = perlinNoise(input.color.xy);
+            // Sample brightness and calculate bloom
+            float brightness = texture(iChannel0, input.color.xy).r;
+            float bloom = max(0.0, brightness - 0.5);
+            if (bloom > 0.5) {
+                bloom = 0.5;
+            } else {
+                bloom = 0.0;
             }
+
+            // Apply bloom to the texture color
+            vec3 texColor = texture(iChannel0, input.color.xy).rgb;
+            vec3 colorWithBloom = texColor + vec3(bloom);
+
+            return vec4(colorWithBloom, 1.0);
         }
     }
+}
 
     """
     try:
@@ -287,32 +365,46 @@ def test_function_call():
 
 def test_assignment_shift_operators():
     code = """
-    shader PerlinNoise {
-    vertex {
-        input vec3 position;
-        output vec2 vUV;
+    shader main {
+
+    struct VSInput {
+        vec2 texCoord @ TEXCOORD0;
+    };
+
+    struct VSOutput {
+        vec4 color @ COLOR;
+    };
+
+    sampler2D iChannel0;
 
-        void main() {
-            vUV = position.xy * 10.0;
-            vUV.x <<= 1;
-            gl_Position = vec4(position, 1.0);
+    vertex {
+        VSOutput main(VSInput input) {
+            VSOutput output;
+            int x = 2;
+            x >>= 1;
+            // Pass through texture coordinates as color
+            output.color = vec4(input.texCoord, 0.0, 1.0);
+
+            return output;
         }
     }
 
-    // Fragment Shader
     fragment {
-        input vec2 vUV;
-        output vec4 fragColor;
-
-        void main() {
-            float noise = perlinNoise(vUV);
-            float height <<= noise * 10.0;
-            vec3 color = vec3(height / 10.0, 1.0 - height / 10.0, 0.0);
-            fragColor = vec4(color, 1.0);
-            }
+        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);
+            int x = 2;
+            x <<= 1;
+
+            // Apply bloom to the texture color
+            vec3 texColor = texture(iChannel0, input.color.xy).rgb;
+            vec3 colorWithBloom = texColor + vec3(bloom);
+
+            return vec4(colorWithBloom, 1.0);
         }
     }
-
+}
     """
     try:
         tokens = tokenize_code(code)
@@ -325,22 +417,51 @@ def test_assignment_shift_operators():
 
 def test_bitwise_operators():
     code = """
-        shader LightControl {
-        vertex {
-            input vec3 position;
-            output int isLightOn;
-            void main() {        
-                    isLightOn = 2 >> 1;
-            }
+    shader main {
+
+    struct VSInput {
+        vec2 texCoord @ TEXCOORD0;
+    };
+
+    struct VSOutput {
+        vec4 color @ COLOR;
+    };
+
+    sampler2D iChannel0;
+
+    vertex {
+        VSOutput main(VSInput input) {
+            VSOutput output;
+            int x = 2;
+            x = x & 1;
+            x = x | 1;
+            x = x + 1;
+
+            // Pass through texture coordinates as color
+            output.color = vec4(input.texCoord, 0.0, 1.0);
+
+            return output;
         }
-        fragment {
-            input int isLightOn;
-            output vec4 fragColor;
-            void main() {
-                isLightOn = isLightOn << 1;
-            }
+    }
+
+    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);
+            int x = 2+ 2;
+            x = x + 1;
+            x = x + 1;
+            x = x + 1;
+
+            // Apply bloom to the texture color
+            vec3 texColor = texture(iChannel0, input.color.xy).rgb;
+            vec3 colorWithBloom = texColor + vec3(bloom);
+
+            return vec4(colorWithBloom, 1.0);
         }
     }
+}
 
     """
     try:
diff --git a/tests/test_translator/test_lexer.py b/tests/test_translator/test_lexer.py
index a1da421..387680c 100644
--- a/tests/test_translator/test_lexer.py
+++ b/tests/test_translator/test_lexer.py
@@ -9,17 +9,21 @@ def tokenize_code(code: str) -> List:
     return lexer.tokens
 
 
-def test_input_output_tokenization():
+def test_struct_tokenization():
     code = """
-    input vec3 position;
-    output vec2 vUV;
-    input vec2 vUV;
-    output vec4 fragColor;
+    struct VSInput {
+        vec2 texCoord @ TEXCOORD0;
+    };
+
+    struct VSOutput {
+        vec4 color @ COLOR;
+    };
+
     """
     try:
         tokenize_code(code)
     except SyntaxError:
-        pytest.fail("Struct parsing not implemented.")
+        pytest.fail("Struct tokenization not implemented.")
 
 
 def test_if_statement_tokenization():
@@ -33,7 +37,7 @@ def test_if_statement_tokenization():
     try:
         tokenize_code(code)
     except SyntaxError:
-        pytest.fail("Struct parsing not implemented.")
+        pytest.fail("if tokenization not implemented.")
 
 
 def test_for_statement_tokenization():
@@ -45,7 +49,7 @@ def test_for_statement_tokenization():
     try:
         tokenize_code(code)
     except SyntaxError:
-        pytest.fail("Struct parsing not implemented.")
+        pytest.fail("for tokenization not implemented.")
 
 
 def test_else_statement_tokenization():
@@ -59,7 +63,7 @@ def test_else_statement_tokenization():
     try:
         tokenize_code(code)
     except SyntaxError:
-        pytest.fail("Struct parsing not implemented.")
+        pytest.fail("else tokenization not implemented.")
 
 
 def test_else_if_statement_tokenization():
@@ -80,42 +84,33 @@ def test_else_if_statement_tokenization():
     try:
         tokenize_code(code)
     except SyntaxError:
-        pytest.fail("Struct parsing not implemented.")
+        pytest.fail("else if  tokenization not implemented.")
 
 
 def test_function_call_tokenization():
     code = """
-    shader PerlinNoise {
-    vertex {
-        input vec3 position;
-        output vec2 vUV;
-
-        void main() {
-            vUV = position.xy * 10.0;
-            gl_Position = vec4(position, 1.0);
-        }
-    }
-
+shader main {
+    
     // Perlin Noise Function
     float perlinNoise(vec2 p) {
         return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453);
     }
-
-    // Fragment Shader
+    
     fragment {
-        input vec2 vUV;
-        output vec4 fragColor;
-
-        void main() {
-            float noise = perlinNoise(vUV);
-            float height = noise * 10.0;
-            vec3 color = vec3(height / 10.0, 1.0 - height / 10.0, 0.0);
-            fragColor = vec4(color, 1.0);
-            }
+        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);
+            bloom = perlinNoise(input.color.xy);
+            // Apply bloom to the texture color
+            vec3 texColor = texture(iChannel0, input.color.xy).rgb;
+            vec3 colorWithBloom = texColor + vec3(bloom);
+
+            return vec4(colorWithBloom, 1.0);
         }
     }
-
-    """
+}
+"""
     try:
         tokenize_code(code)
     except SyntaxError:
diff --git a/tests/test_translator/test_parser.py b/tests/test_translator/test_parser.py
index c02468d..2bcd5c7 100644
--- a/tests/test_translator/test_parser.py
+++ b/tests/test_translator/test_parser.py
@@ -22,29 +22,16 @@ def parse_code(tokens: List):
     return parser.parse()
 
 
-def test_input_output():
+def test_struct_tokenization():
     code = """
-    shader PerlinNoise {
-    vertex {
-        input vec3 position;
-        output vec2 vUV;
+    struct VSInput {
+        vec2 texCoord @ TEXCOORD0;
+    };
 
-        void main() {
-            vUV = position.xy * 10.0;
-            gl_Position = vec4(position, 1.0);
-        }
-    }
-
-    // Fragment Shader
-    fragment {
-        input vec2 vUV;
-        output vec4 fragColor;
+    struct VSOutput {
+        vec4 color @ COLOR;
+    };
 
-        void main() {
-            fragColor = vec4(color, 1.0);
-            }
-        }
-    }
     """
     try:
         tokens = tokenize_code(code)
@@ -55,279 +42,307 @@ def test_input_output():
 
 def test_if_statement():
     code = """
-    shader PerlinNoise {
+    shader main {
+
+    struct VSInput {
+        vec2 texCoord @ TEXCOORD0;
+    };
+
+    struct VSOutput {
+        vec4 color @ COLOR;
+    };
+
+    sampler2D iChannel0;
+
     vertex {
-        input vec3 position;
-        output vec2 vUV;
+        VSOutput main(VSInput input) {
+            VSOutput output;
 
-        void main() {
-            vUV = position.xy * 10.0;
-            if (vUV.x > 0.5) {
-                vUV.x = 0.5;
+            if (input.texCoord.x > 0.5) {
+                output.color = vec4(1.0, 1.0, 1.0, 1.0);
+            } else {
+                output.color = vec4(0.0, 0.0, 0.0, 1.0);
             }
 
-            gl_Position = vec4(position, 1.0);
+            // Pass through texture coordinates as color
+            output.color = vec4(input.texCoord, 0.0, 1.0);
+
+            return output;
         }
     }
 
-    // Fragment Shader
     fragment {
-        input vec2 vUV;
-        output vec4 fragColor;
-
-        void main() {
-                if (vUV.x > 0.5) {
-                fragColor = vec4(1.0, 1.0, 1.0, 1.0);
-                }
-            fragColor = vec4(color, 1.0);
+        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);
+            if (bloom > 0.5) {
+                bloom = 0.5;
+            } else {
+                bloom = 0.0;
             }
+
+            // Apply bloom to the texture color
+            vec3 texColor = texture(iChannel0, input.color.xy).rgb;
+            vec3 colorWithBloom = texColor + vec3(bloom);
+
+            return vec4(colorWithBloom, 1.0);
         }
     }
-    """
+}
+
+"""
     try:
         tokens = tokenize_code(code)
         parse_code(tokens)
     except SyntaxError:
-        pytest.fail("Struct parsing not implemented.")
+        pytest.fail("if statement parsing not implemented.")
 
 
 def test_for_statement():
     code = """
-    shader PerlinNoise {
-    vertex {
-        input vec3 position;
-        output vec2 vUV;
+    shader main {
 
-        void main() {
-            vUV = position.xy * 10.0;
-            for (int i = 0; i < 10; i = i + 1) {
-                vUV = vec2(0.0, 0.0);
-            }
-            gl_Position = vec4(position, 1.0);
-        }
-    }
-
-    // Fragment Shader
-    fragment {
-        input vec2 vUV;
-        output vec4 fragColor;
+    struct VSInput {
+        vec2 texCoord @ TEXCOORD0;
+    };
 
-        void main() {
-            for (int i = 0; i < 10; i = i + 1) {
-                vec3 color = vec3(1.0, 1.0, 1.0);
-            }
-            fragColor = vec4(color, 1.0);
-            }
-        }
-    }
-    """
-    try:
-        tokens = tokenize_code(code)
-        parse_code(tokens)
-    except SyntaxError:
-        pytest.fail("Struct parsing not implemented.")
+    struct VSOutput {
+        vec4 color @ COLOR;
+    };
 
+    sampler2D iChannel0;
 
-def test_else_statement():
-    code = """
-    shader PerlinNoise {
     vertex {
-        input vec3 position;
-        output vec2 vUV;
+        VSOutput main(VSInput input) {
+            VSOutput output;
 
-        void main() {
-            vUV = position.xy * 10.0;
-            if (vUV.x > 0.5) {
-                vUV.x = 0.5;
-            } else {
-                vUV.x = 0.0;
+            for (int i = 0; i < 10; i++) {
+                output.color = vec4(1.0, 1.0, 1.0, 1.0);
             }
-            gl_Position = vec4(position, 1.0);
-        }
-    }
-
-    // Fragment Shader
-    fragment {
-        input vec2 vUV;
-        output vec4 fragColor;
+            // Pass through texture coordinates as color
+            output.color = vec4(input.texCoord, 0.0, 1.0);
 
-        void main() {
-            if (vUV.x > 0.5) {
-            fragColor = vec4(1.0, 1.0, 1.0, 1.0);
-            } else {
-                fragColor = vec4(0.0, 0.0, 0.0, 1.0);
-            }
-            fragColor = vec4(color, 1.0);
-            }
+            return output;
         }
     }
-    """
+}
+
+"""
     try:
         tokens = tokenize_code(code)
         parse_code(tokens)
     except SyntaxError:
-        pytest.fail("Struct parsing not implemented.")
+        pytest.fail("for parsing not implemented.")
 
 
 def test_else_if_statement():
     code = """
-    shader PerlinNoise {
+    shader main {
+
+    struct VSInput {
+        vec2 texCoord @ TEXCOORD0;
+    };
+
+    struct VSOutput {
+        vec4 color @ COLOR;
+    };
+
+    sampler2D iChannel0;
+
     vertex {
-        input vec3 position;
-        output vec2 vUV;
+        VSOutput main(VSInput input) {
+            VSOutput output;
 
-        void main() {
-            vUV = position.xy * 10.0;
-            if (vUV.x < 0.5) {
-                vUV.x = 0.25;
-            }
-            if (vUV.x < 0.25) {
-                vUV.x = 0.0;
-            } else if (vUV.x < 0.75) {
-                vUV.x = 0.5;
-            } else if (vUV.x < 1.0) {
-                vUV.x = 0.75;
+            if (input.texCoord.x > 0.5) {
+                output.color = vec4(1.0, 1.0, 1.0, 1.0);
+            } else if (input.texCoord.x < 0.5) {
+                output.color = vec4(0.0, 0.0, 0.0, 1.0);
             } else {
-                vUV.x = 0.0;
-            }
-            gl_Position = vec4(position, 1.0);
+                output.color = vec4(0.5, 0.5, 0.5, 1.0);
+
+            // Pass through texture coordinates as color
+            output.color = vec4(input.texCoord, 0.0, 1.0);
+
+            return output;
         }
     }
+}
 
-    // Fragment Shader
     fragment {
-        input vec2 vUV;
-        output vec4 fragColor;
-
-        void main() {
-            if (vUV.x > 0.75) {
-                fragColor = vec4(1.0, 1.0, 1.0, 1.0);
-            } else if (vUV.x > 0.5) {
-                fragColor = vec4(0.5, 0.5, 0.5, 1.0);
-            } else if (vUV.x > 0.25) {
-                fragColor = vec4(0.25, 0.25, 0.25, 1.0);
+        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);
+            if (bloom > 0.5) {
+                bloom = 0.5;
+            } else if (bloom < 0.5) {
+                bloom = 0.0;
             } else {
-                fragColor = vec4(0.0, 0.0, 0.0, 1.0);
-            }
-            fragColor = vec4(color, 1.0);
+                bloom = 0.5;
             }
+            // Apply bloom to the texture color
+            vec3 texColor = texture(iChannel0, input.color.xy).rgb;
+            vec3 colorWithBloom = texColor + vec3(bloom);
+
+            return vec4(colorWithBloom, 1.0);
         }
     }
-    """
+}
+
+"""
     try:
         tokens = tokenize_code(code)
         parse_code(tokens)
     except SyntaxError:
-        pytest.fail("Struct parsing not implemented.")
+        pytest.fail("else if statement parsing not implemented.")
 
 
 def test_function_call():
     code = """
-    shader PerlinNoise {
-    vertex {
-        input vec3 position;
-        output vec2 vUV;
+    shader main {
 
-        void main() {
-            vUV = position.xy * 10.0;
-            gl_Position = vec4(position, 1.0);
-        }
+    struct VSInput {
+        vec2 texCoord @ TEXCOORD0;
+    };
+
+    struct VSOutput {
+        vec4 color @ COLOR;
+    };
+
+    sampler2D iChannel0;
+
+    vec4 addColor(vec4 color1, vec4 color2) {
+        return color1 + color2;
     }
 
-    // Perlin Noise Function
-    float perlinNoise(vec2 p) {
-        return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453);
+    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));
+            // Pass through texture coordinates as color
+            output.color = vec4(input.texCoord, 0.0, 1.0);
+            return output;
+        }
     }
 
-    // Fragment Shader
     fragment {
-        input vec2 vUV;
-        output vec4 fragColor;
-
-        void main() {
-            float noise = perlinNoise(vUV);
-            float height = noise * 10.0;
-            vec3 color = vec3(height / 10.0, 1.0 - height / 10.0, 0.0);
-            fragColor = vec4(color, 1.0);
-            }
+        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
+            vec3 texColor = texture(iChannel0, input.color.xy).rgb;
+            vec3 colorWithBloom = texColor + vec3(bloom);
+            return vec4(colorWithBloom, 1.0);
         }
     }
-
+}
     """
     try:
         tokens = tokenize_code(code)
         parse_code(tokens)
     except SyntaxError:
-        pytest.fail("Struct parsing not implemented.")
+        pytest.fail("function call parsing not implemented.")
 
 
 def test_assign_shift_right():
     code = """
-    shader PerlinNoise {
-    vertex {
-        input vec3 position;
-        output vec2 vUV;
+    shader main {
+
+    struct VSInput {
+        vec2 texCoord @ TEXCOORD0;
+    };
 
-        void main() {
-            vUV >>= 1;
-            vUV = position.xy * 10.0;
-            gl_Position = vec4(position, 1.0);
+    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;
+            uint b = 2;
+            // Pass through texture coordinates as color
+            output.color = vec4(input.texCoord, 0.0, 1.0);
+            return output;
         }
     }
 
-    // Fragment Shader
     fragment {
-        input vec2 vUV;
-        output vec4 fragColor;
-
-        void main() {
-            double noise = fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453);
-            double height = noise * 10.0;
+        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;
             uint b = 2;
-            vec3 color = vec3(height / 10.0, 1.0 - height / 10.0, 0.0);
-            fragColor = vec4(color, 1.0);
-            }
+            vec3 texColor = texture(iChannel0, input.color.xy).rgb;
+            vec3 colorWithBloom = texColor + vec3(bloom);
+            return vec4(colorWithBloom, 1.0);
         }
     }
+}
     """
 
     try:
         tokens = tokenize_code(code)
-        print(parse_code(tokens))
+        parse_code(tokens)
     except SyntaxError as e:
         pytest.fail(f"Failed to parse ASSIGN_SHIFT_RIGHT token: {e}")
 
 
 def test_logical_operators():
     code = """
-        shader LightControl {
-        vertex {
-            input vec3 position;
-            output float isLightOn;
-            void main() {
-                // Using logical AND and logical OR operators
-                if ((position.x > 0.3 && position.z < 0.7) || position.y > 0.5) {
-                    isLightOn = 1.0;
-                } else {
-                    isLightOn = 0.0;
-                }
-                // Set the vertex position
-                gl_Position = vec4(position, 1.0);
+    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));
+            // Using logical AND and logical OR operators
+            if ((position.x > 0.3 && position.z < 0.7) || position.y > 0.5) {
+                isLightOn = 1.0;
+            } else {
+                isLightOn = 0.0;
             }
+            // Pass through texture coordinates as color
+            output.color = vec4(input.texCoord, 0.0, 1.0);
+            return output;
         }
-        fragment {
-            input float isLightOn;
-            output vec4 fragColor;
-            void main() {
-                if (isLightOn == 1.0) {
-                    fragColor = vec4(1.0, 1.0, 0.0, 1.0);  // Light is on
-                } else {
-                    fragColor = vec4(0.0, 0.0, 0.0, 1.0);  // Light is off
-                }
+    }
+
+    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
+            // Using logical AND and logical OR operators
+            if ((position.x > 0.3 && position.z < 0.7) || position.y > 0.5) {
+                isLightOn = 1.0;
+            } else {
+                isLightOn = 0.0;
             }
+            vec3 texColor = texture(iChannel0, input.color.xy).rgb;
+            vec3 colorWithBloom = texColor + vec3(bloom);
+            return vec4(colorWithBloom, 1.0);
         }
     }
+}
     """
     try:
         tokens = tokenize_code(code)
@@ -338,34 +353,47 @@ def test_logical_operators():
 
 def test_var_assignment():
     code = """
-    shader PerlinNoise {
-    vertex {
-        input vec3 position;
-        output vec2 vUV;
+    shader main {
+    struct VSInput {
+        vec2 texCoord @ TEXCOORD0;
+    };
 
-        void main() {
-            vUV = position.xy * 10.0;
-            gl_Position = vec4(position, 1.0);
+    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));
+            double noise = fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453);
+            double height = noise * 10.0;
+            uint a = 1;
+            uint b = 2;
+            // Pass through texture coordinates as color
+            output.color = vec4(input.texCoord, 0.0, 1.0);
+            return output;
         }
     }
 
-    // Fragment Shader
     fragment {
-        input vec2 vUV;
-        output vec4 fragColor;
-
-        void main() {
+        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);
             double noise = fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453);
             double height = noise * 10.0;
             uint a = 1;
             uint b = 2;
-            vec3 color = vec3(height / 10.0, 1.0 - height / 10.0, 0.0);
-            fragColor = vec4(color, 1.0);
-            }
+            vec3 texColor = texture(iChannel0, input.color.xy).rgb;
+            vec3 colorWithBloom = texColor + vec3(bloom);
+            return vec4(colorWithBloom, 1.0);
         }
     }
-
-    """
+}
+"""
     try:
         tokens = tokenize_code(code)
         parse_code(tokens)
@@ -374,42 +402,58 @@ def test_var_assignment():
 
 
 def test_assign_ops():
-
     code = """
-            shader LightControl {
-                vertex {
-                    input vec3 position;
-                    output int lightStatus;
-
-                    void main() {
-                        int xStatus = int(position.x * 10.0);
-                        int yStatus = int(position.y * 10.0);
-                        int zStatus = int(position.z * 10.0);
-
-                        xStatus |= yStatus;
-                        yStatus &= zStatus;
-                        zStatus %= xStatus;
-                        lightStatus = xStatus;
-                        lightStatus ^= zStatus;
-
-                        gl_Position = vec4(position, 1.0);
-                    }
-                }
-
-                fragment {
-                    input int lightStatus;
-                    output vec4 fragColor;
-
-                    void main() {
-                        if (lightStatus > 0) {
-                            fragColor = vec4(1.0, 1.0, 0.0, 1.0); 
-                        } else {
-                            fragColor = vec4(0.0, 0.0, 0.0, 1.0);
-                        }
-                    }
-                }
-            }
-        """
+    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));
+            int xStatus = int(position.x * 10.0);
+            int yStatus = int(position.y * 10.0);
+            int zStatus = int(position.z * 10.0);
+
+            xStatus |= yStatus;
+            yStatus &= zStatus;
+            zStatus %= xStatus;
+            lightStatus = xStatus;
+            lightStatus ^= zStatus;
+            // 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);
+            int xStatus = int(position.x * 10.0);
+            int yStatus = int(position.y * 10.0);
+            int zStatus = int(position.z * 10.0);
+
+            xStatus |= yStatus;
+            yStatus &= zStatus;
+            zStatus %= xStatus;
+            lightStatus = xStatus;
+            lightStatus ^= zStatus;
+            vec3 texColor = texture(iChannel0, input.color.xy).rgb;
+            vec3 colorWithBloom = texColor + vec3(bloom);
+            return vec4(colorWithBloom, 1.0);
+        }
+    }
+}
+"""
     try:
         tokens = tokenize_code(code)
         parse_code(tokens)
@@ -419,24 +463,41 @@ def test_assign_ops():
 
 def test_bitwise_operators():
     code = """
-        shader LightControl {
-        vertex {
-            input vec3 position;
-            output int isLightOn;
-            void main() {        
-                    isLightOn = 2 >> 1;
-            }
-        }
-        fragment {
-            input int isLightOn;
-            output vec4 fragColor;
-            void main() {
-                isLightOn = isLightOn << 1;
-            }
+    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));
+            isLightOn = 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);
+            isLightOn = isLightOn << 1;
+            vec3 texColor = texture(iChannel0, input.color.xy).rgb;
+            vec3 colorWithBloom = texColor + vec3(bloom);
+            return vec4(colorWithBloom, 1.0);
+        }
+    }
+}
+"""
     try:
         tokens = tokenize_code(code)
         parse_code(tokens)
@@ -446,30 +507,42 @@ def test_bitwise_operators():
 
 def test_xor_operator():
     code = """
-    shader XorTestShader {
-    vertex {
-        input vec3 position;
-        output vec2 vUV;
+    shader main {
+    struct VSInput {
+        vec2 texCoord @ TEXCOORD0;
+    };
+
+    struct VSOutput {
+        vec4 color @ COLOR;
+    };
 
-        void main() {
-            // Perform XOR on the x and y components of the position
+    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));
             vUV.x = float(int(position.x) ^ 3);  // XOR with 3
             vUV.y = float(int(position.y) ^ 5);  // XOR with 5
-            gl_Position = vec4(position, 1.0);
+            // Pass through texture coordinates as color
+            output.color = vec4(input.texCoord, 0.0, 1.0);
+            return output;
         }
     }
 
     fragment {
-        input vec2 vUV;
-        output vec4 fragColor;
-
-        void main() {
-            // Use XOR in fragment shader
-            float result = float(int(vUV.x) ^ int(vUV.y));
-            fragColor = vec4(result / 10.0, 1.0 - result / 10.0, 0.0, 1.0);
+        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);
+            vUV.x = float(int(position.x) ^ 3);  // XOR with 3
+            vUV.y = float(int(position.y) ^ 5);  // XOR with 5
+            vec3 texColor = texture(iChannel0, input.color.xy).rgb;
+            vec3 colorWithBloom = texColor + vec3(bloom);
+            return vec4(colorWithBloom, 1.0);
         }
     }
-    }
+}
     """
     try:
         tokens = tokenize_code(code)