Repository: CrossGL/crosstl

Issue:
Add `Assignment Shift Left`  Token at translator frontend 
Implement the ASSIGN_SHIFT_LEFT token to recognize the <<= operator for performing left bitwise shift assignments.

Discussion:
dotdot0: Accidentally created a new branch from the branch of my prev PR that's why those changes are there.
samthakur587: hii @dotdot0 can you please resolve the merge conflicts 

Patch:
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index fe342d4..32aefc7 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1,7 +1,5 @@
 * @NripeshN
 
-crosstl/* @samthakur587
+crosstl/* @samthakur587 @vaatsalya123
 
 tests/* @samthakur587
-
-crosstl/* @vaatsalya123
\ No newline at end of file
diff --git a/.github/workflows/assign_pull_request.yml b/.github/workflows/assign_pull_request.yml
deleted file mode 100644
index 51b09d1..0000000
--- a/.github/workflows/assign_pull_request.yml
+++ /dev/null
@@ -1,36 +0,0 @@
-name: Assign PR to Code Owner
-
-on:
-  pull_request:
-    types: [opened]
-
-jobs:
-  assign_pr:
-    runs-on: ubuntu-latest
-    steps:
-      - name: Check out repository
-        uses: actions/checkout@v2
-
-      - name: Set up GitHub CLI
-        run: |
-          sudo apt-get update
-          sudo apt-get install gh -y
-
-      - name: Get Code Owners
-        id: get-code-owners
-        run: |
-          CODEOWNERS_FILE=.github/CODEOWNERS
-          if [ -f "$CODEOWNERS_FILE" ]; then
-            CODE_OWNER=$(grep -v '^#' $CODEOWNERS_FILE | grep -Eo '@[a-zA-Z0-9_-]+' | head -n 1)
-            echo "code_owner=${CODE_OWNER#@}" >> $GITHUB_ENV
-          else
-            echo "No CODEOWNERS file found."
-            exit 1
-          fi
-
-      - name: Assign PR to Code Owner
-        if: env.code_owner != ''
-        env:
-          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-        run: |
-          gh pr edit ${{ github.event.pull_request.number }} --add-assignee "${{ env.code_owner }}"
\ No newline at end of file
diff --git a/crosstl/src/translator/lexer.py b/crosstl/src/translator/lexer.py
index b79abe1..74a4b79 100644
--- a/crosstl/src/translator/lexer.py
+++ b/crosstl/src/translator/lexer.py
@@ -21,6 +21,8 @@ TOKENS = [
     ("DOUBLE", r"\bdouble\b"),
     ("SAMPLER2D", r"\bsampler2D\b"),
     ("IDENTIFIER", r"[a-zA-Z_][a-zA-Z_0-9]*"),
+    ("ASSIGN_SHIFT_RIGHT", r">>="),
+    ("ASSIGN_SHIFT_LEFT", r"<<="),
     ("NUMBER", r"\d+(\.\d+)?"),
     ("LBRACE", r"\{"),
     ("RBRACE", r"\}"),
diff --git a/crosstl/src/translator/parser.py b/crosstl/src/translator/parser.py
index c62c6b1..51ad041 100644
--- a/crosstl/src/translator/parser.py
+++ b/crosstl/src/translator/parser.py
@@ -90,6 +90,8 @@ class Parser:
             if self.current_token[0] in [
                 "VECTOR",
                 "FLOAT",
+                "DOUBLE",
+                "UINT",
                 "INT",
                 "SAMPLER2D",
                 "MATRIX",
@@ -98,7 +100,7 @@ class Parser:
                 self.eat(self.current_token[0])
             else:
                 raise SyntaxError(
-                    f"Expected VECTOR, FLOAT, INT, or SAMPLER2D, got {self.current_token[0]}"
+                    f"Expected VECTOR, FLOAT, DOUBLE, UINT, INT or SAMPLER2D, got {self.current_token[0]}"
                 )
             name = self.current_token[1]
             self.eat("IDENTIFIER")
@@ -157,7 +159,15 @@ class Parser:
             elif self.current_token[0] == "FRAGMENT":
                 fragment_section = self.parse_shader_section("FRAGMENT")
                 self.skip_comments()  # Skip comments while parsing functions
-            elif self.current_token[0] in ["VECTOR", "FLOAT", "INT", "VOID", "MATRIX"]:
+            elif self.current_token[0] in [
+                "VECTOR",
+                "FLOAT",
+                "DOUBLE",
+                "UINT",
+                "INT",
+                "VOID",
+                "MATRIX",
+            ]:
                 global_functions.append(self.parse_function())
                 self.skip_comments()  # Skip comments while parsing functions
             else:
@@ -202,7 +212,8 @@ class Parser:
             elif self.current_token[0] == "OUTPUT":
                 outputs.extend(self.parse_outputs())
             elif (
-                self.current_token[0] in ["VECTOR", "FLOAT", "INT", "VOID", "MATRIX"]
+                self.current_token[0]
+                in ["VECTOR", "FLOAT", "DOUBLE", "UINT", "INT", "VOID", "MATRIX"]
                 and self.peak(2)[0] == "LPAREN"
             ):
                 functions.append(self.parse_function())
@@ -214,6 +225,8 @@ class Parser:
                 "VECTOR",
                 "IDENTIFIER",
                 "FLOAT",
+                "DOUBLE",
+                "UINT",
                 "INT",
                 "MATRIX",
             ]:
@@ -248,6 +261,8 @@ class Parser:
             if self.current_token[0] in [
                 "VECTOR",
                 "FLOAT",
+                "DOUBLE",
+                "UINT",
                 "INT",
                 "MATRIX",
                 "SAMPLER2D",
@@ -256,7 +271,7 @@ class Parser:
                 self.eat(self.current_token[0])
             else:
                 raise SyntaxError(
-                    f"Expected VECTOR, FLOAT, INT, MATRIX, or SAMPLER2D, got {self.current_token[0]}"
+                    f"Expected VECTOR, FLOAT, DOUBLE, UINT, INT, MATRIX, or SAMPLER2D, got {self.current_token[0]}"
                 )
             name = self.current_token[1]
             self.eat("IDENTIFIER")
@@ -285,6 +300,8 @@ class Parser:
             if self.current_token[0] in [
                 "VECTOR",
                 "FLOAT",
+                "DOUBLE",
+                "UINT",
                 "INT",
                 "MATRIX",
                 "SAMPLER2D",
@@ -293,7 +310,7 @@ class Parser:
                 self.eat(self.current_token[0])
             else:
                 raise SyntaxError(
-                    f"Expected VECTOR, FLOAT, INT, MATRIX, or SAMPLER2D, got {self.current_token[0]}"
+                    f"Expected VECTOR, FLOAT, DOUBLE, UINT, INT, MATRIX, or SAMPLER2D, got {self.current_token[0]}"
                 )
             name = self.current_token[1]
             self.eat("IDENTIFIER")
@@ -386,14 +403,22 @@ class Parser:
         if self.current_token[0] == "VOID":
             self.eat("VOID")
             return "void"
-        elif self.current_token[0] in ["VECTOR", "FLOAT", "INT", "MATRIX", "SAMPLER2D"]:
+        elif self.current_token[0] in [
+            "VECTOR",
+            "FLOAT",
+            "DOUBLE",
+            "UINT",
+            "INT",
+            "MATRIX",
+            "SAMPLER2D",
+        ]:
             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]
             self.eat("IDENTIFIER")
-            if type_name in ["int", "float"]:
+            if type_name in ["int", "uint", "float", "double"]:
                 return type_name
             return type_name
         else:
@@ -417,7 +442,14 @@ class Parser:
                 body.append(self.parse_for_loop())
             elif self.current_token[0] == "RETURN":
                 body.append(self.parse_return_statement())
-            elif self.current_token[0] in ["VECTOR", "IDENTIFIER", "FLOAT", "INT"]:
+            elif self.current_token[0] in [
+                "VECTOR",
+                "IDENTIFIER",
+                "FLOAT",
+                "DOUBLE",
+                "UINT",
+                "INT",
+            ]:
                 body.append(self.parse_assignment_or_function_call())
             else:
                 raise SyntaxError(f"Unexpected token {self.current_token[0]}")
@@ -563,7 +595,14 @@ class Parser:
         """
         type_name = ""
         inc_dec = False
-        if self.current_token[0] in ["VECTOR", "FLOAT", "INT", "MATRIX"]:
+        if self.current_token[0] in [
+            "VECTOR",
+            "FLOAT",
+            "DOUBLE",
+            "UINT",
+            "INT",
+            "MATRIX",
+        ]:
             type_name = self.current_token[1]
             self.eat(self.current_token[0])
         if self.current_token[0] == "IDENTIFIER":
@@ -810,6 +849,8 @@ class Parser:
             "IDENTIFIER",
             "VECTOR",
             "FLOAT",
+            "DOUBLE",
+            "UINT",
             "INT",
             "MATRIX",
         ]:
@@ -908,7 +949,14 @@ class Parser:
             ASTNode: An ASTNode object representing the function call or identifier
 
         """
-        if self.current_token[0] in ["VECTOR", "FLOAT", "INT", "MATRIX"]:
+        if self.current_token[0] in [
+            "VECTOR",
+            "FLOAT",
+            "DOUBLE",
+            "UINT",
+            "INT",
+            "MATRIX",
+        ]:
             func_name = self.current_token[1]
             self.eat(self.current_token[0])
         else:


Test patch:
diff --git a/tests/test_translator/test_lexer.py b/tests/test_translator/test_lexer.py
index dcc1c2d..754ba6a 100644
--- a/tests/test_translator/test_lexer.py
+++ b/tests/test_translator/test_lexer.py
@@ -159,7 +159,19 @@ def test_logical_operators_tokenization():
     try:
         tokenize_code(code)
     except SyntaxError:
-        pytest.fail("Logical operators tokenization not implemented.")
+        pytest.fail("Logical Operators tokenization not implemented.")
+
+
+def test_assignment_shift_operators():
+    code = """
+    a >>= 1;
+    b <<= 1;
+        """
+
+    try:
+        tokenize_code(code)
+    except SyntaxError:
+        pytest.fail("Shift operators tokenization failed.")
 
 
 def test_assignment_operators_tokenization():
diff --git a/tests/test_translator/test_parser.py b/tests/test_translator/test_parser.py
index ab39356..a12a3ad 100644
--- a/tests/test_translator/test_parser.py
+++ b/tests/test_translator/test_parser.py
@@ -244,3 +244,40 @@ def test_logical_operators():
         parse_code(tokens)
     except SyntaxError:
         pytest.fail("Struct parsing not implemented.")
+
+
+def test_var_assignment():
+    code = """
+    shader PerlinNoise {
+    vertex {
+        input vec3 position;
+        output vec2 vUV;
+
+        void main() {
+            vUV = position.xy * 10.0;
+            gl_Position = vec4(position, 1.0);
+        }
+    }
+
+    // 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;
+            uint a = 1;
+            uint b = 2;
+            vec3 color = vec3(height / 10.0, 1.0 - height / 10.0, 0.0);
+            fragColor = vec4(color, 1.0);
+            }
+        }
+    }
+
+    """
+    try:
+        tokens = tokenize_code(code)
+        parse_code(tokens)
+    except SyntaxError:
+        pytest.fail("Variable assignment parsing not implemented.")