1
0
Johan Rong 3 долоо хоног өмнө
parent
commit
93332d0597

+ 7 - 3
src/zelkelc/__main__.py

@@ -5,12 +5,16 @@ from src.zelkelc.codegen.codegen import Codegen
 import rich
 
 source = """
+struct MyStruct {
+    val test: i64
+}
+
 //test
 class MyClass {
-    val immutable_value: i64
-    var mutable_value: String
+    val immutable_value: i64 = 12
+    var mutable_value: i64 = "sjdhfjsd"
     
-    fn function(test: i64, test2: String) -> void {
+    fn function(test: i64, test2: i64) -> void {
         return 0
     }
 }

+ 18 - 1
src/zelkelc/ast/nodes.py

@@ -1,14 +1,29 @@
 from __future__ import annotations
+from typing import Optional
 
 from dataclasses import dataclass
 import src.zelkelc.ast.values as values
-import src.zelkelc.ast.scope as scope
 
 @dataclass
 class ClassDeclaration:
     name: str
     members: list[ValueDeclaration]
     methods: list[FunctionDeclaration]
+    real_name: str
+
+@dataclass
+class StructDeclaration:
+    name: str
+    members: list[ValueDeclaration]
+    real_name: str
+
+@dataclass
+class MemberDeclaration:
+    name: str
+    mutable: bool
+    typ: values.Value
+    real_name: str
+    real_idx: int
 
 @dataclass
 class ValueDeclaration:
@@ -16,6 +31,7 @@ class ValueDeclaration:
     mutable: bool
     typ: values.Value
     expr: Expression
+    real_name: str
     
 @dataclass
 class FunctionDeclaration:
@@ -23,6 +39,7 @@ class FunctionDeclaration:
     typ: values.Value
     args: dict[str, values.Value]
     body: list[Node]
+    real_name: str
     
 @dataclass
 class ReturnStatement:

+ 65 - 5
src/zelkelc/ast/parser.py

@@ -1,10 +1,12 @@
 import src.zelkelc.lexer.token as token
 import src.zelkelc.ast.nodes as nodes
 import src.zelkelc.ast.values as values
+import src.zelkelc.ast.scope as scope
 
 class Parser:
     tokens: list[token.Token]
     cursor: int
+    scopes: list[scope.Scope]
     
     def __init__(self, tokens: list[token.Token], cursor: int):
         self.tokens = tokens
@@ -57,6 +59,8 @@ class Parser:
                     match t.value:
                         case "fn":
                             ast.append(self.parse_function_declaration())
+                        case "struct":
+                            ast.append(self.parse_struct_declaration())
                         case "class":
                             ast.append(self.parse_class_declaration())
                         case _:
@@ -68,6 +72,62 @@ class Parser:
                             
         
         return ast
+
+    def parse_struct_declaration(self) -> nodes.StructDeclaration:
+        self.expect(token.Identifier("struct"))
+        name = self.expect_type(token.Identifier).value
+        self.expect(token.LBrace())
+        
+        members = self.parse_struct_declaration_body(name)
+        
+        self.expect(token.RBrace())
+        
+        return nodes.StructDeclaration(
+            name,
+            members,
+            real_name = f"s_{name}"
+        )
+        
+    def parse_struct_declaration_body(self, struct_name: str) -> list[nodes.MemberDeclaration]:
+        members: list[nodes.MemberDeclaration] = []
+                
+        while self.cursor < len(self.tokens) and not self.tokens[self.cursor] == token.RBrace():
+            t = self.tokens[self.cursor]
+            
+            match t:
+                case token.Identifier():
+                    match t.value:
+                        case "val":
+                            members.append(self.parse_member_declaration(False, struct_name, len(members)))
+                        case "var":
+                            members.append(self.parse_member_declaration(True, struct_name, len(members)))
+                        case _:
+                            print(f"Invalid keyword in struct body {t.value}")
+                            exit(1)
+                case _:
+                    print(f"Invalid token found while parsing class declaration: {t}")
+                    exit(1)
+                            
+        return members
+    
+    def parse_member_declaration(self, mutable: bool, struct_name: str, member_idx) -> nodes.MemberDeclaration:
+        if mutable:
+            self.expect(token.Identifier("var"))
+        else:
+            self.expect(token.Identifier("val"))
+        
+        name = self.expect_type(token.Identifier).value
+        
+        self.expect(token.Colon())
+        typ = self.parse_type(False)
+        
+        return nodes.MemberDeclaration(
+            name,
+            mutable,
+            typ,
+            real_name = f"s_m_{struct_name}_{member_idx}_{name}",
+            real_idx=member_idx
+        )
     
     def parse_class_declaration(self) -> nodes.ClassDeclaration:
         self.expect(token.Identifier("class"))
@@ -95,7 +155,7 @@ class Parser:
                 case token.Identifier():
                     match t.value:
                         case "fn":
-                            methods.append(self.parse_function_declaration(False))
+                            methods.append(self.parse_function_declaration())
                         case "val":
                             members.append(self.parse_value_declaration(False))
                         case "var":
@@ -116,14 +176,14 @@ class Parser:
         
         args: dict[str, values.Value] = {}
         while self.cursor < len(self.tokens) and not self.current(token.RParen()):
-            name = self.expect_type(token.Identifier).value
-            if name in args:
-                print(f"Cannot define argument {name} twice")
+            arg_name = self.expect_type(token.Identifier).value
+            if arg_name in args:
+                print(f"Cannot define argument {arg_name} twice")
                 exit(1)
             
             self.expect(token.Colon())
             typ = self.parse_type(False)
-            args[name] = typ
+            args[arg_name] = typ
             
             if not self.current(token.Comma()):
                 break

+ 3 - 4
src/zelkelc/ast/scope.py

@@ -25,7 +25,6 @@ class ValueInfo:
 
 @dataclass
 class Scope:
-    classes: nodes.ClassDeclaration
-    functions: nodes.FunctionDeclaration    
-    variables: nodes.ValueDeclaration
-    child: Scope | None
+    classes: nodes.ClassDeclaration # burde ikkje bruke node, fordi den har masse unødvendig info, trenger berre navn, real_name, real_idx, ..., args, static,mutable, type, osv
+    functions: nodes.FunctionDeclaration # burde ikkje bruke node, fordi den har masse unødvendig info, trenger berre navn, real_name, real_idx, ..., args, static,mutable, type, osv
+    variables: nodes.ValueDeclaration # burde ikkje bruke node, fordi den har masse unødvendig info, trenger berre navn, real_name, real_idx, ..., args, static,mutable, type, osv

+ 25 - 10
src/zelkelc/codegen/codegen.py

@@ -17,29 +17,44 @@ class Codegen:
         self.ast = ast
         self.ir = IRTable("", "", "")
         
-    def generate(self) -> str:
+    def generate(self):
         for node in self.ast:
             match node:
+                case nodes.StructDeclaration():
+                    self.gen_struct_declaration(node)
+                case nodes.ClassDeclaration():
+                    self.gen_class_declaration(node)
                 case nodes.FunctionDeclaration():
                     self.ir.global_functions += self.gen_function_declaration(node)
-                case nodes.ClassDeclaration():
-                    self.ir.structs += self.gen_class_declaration(node)
+                case _:
+                    print(f"Invalid node found during codegen {type(node)}")
+                    exit(1)
         
         return self.ir.structs + "\n" + self.ir.struct_functions + "\n" + self.ir.global_functions
+    
+    def gen_struct_declaration(self, node: nodes.StructDeclaration):
+        members_str = ""
+        for i, m in enumerate(node.members):
+            members_str += f"{", " if i != 0 else ""}{m.typ.to_llvm()}"
+
+        self.ir.structs += f"\n%{node.real_name} = type " + "{ " + members_str + " }"
 
-    def gen_class_declaration(self, node: nodes.ClassDeclaration) -> str:
+    def gen_class_declaration(self, node: nodes.ClassDeclaration):
         members_str = ""
         for i, m in enumerate(node.members):
             members_str += f"{", " if i != 0 else ""}{m.typ.to_llvm()}"
         
-        return f"\n%{node.name} = type " + "{ " + members_str + " }"
+        self.ir.structs += f"\n%{node.real_name} = type " + "{ " + members_str + " }"
+        
+        for func in node.methods:
+            self.ir.struct_functions += self.gen_function_declaration(func)
     
     def gen_function_declaration(self, node: nodes.FunctionDeclaration) -> str:
         args_str = ""
         for i, (name, typ) in enumerate(node.args.items()):
             args_str += f"{", " if i != 0 else ""}{typ.to_llvm()} %{name}"
-        
-        ir = f"define {str(node.typ.to_llvm())} @{node.name}({args_str}) " + "{"
+            
+        ir = f"\ndefine {str(node.typ.to_llvm())} @{node.real_name}({args_str}) " + "{"
         ir += "\nentry:"
         
         for child_node in node.body:
@@ -55,9 +70,9 @@ class Codegen:
         ir = "\n"
         
         if node.mutable == True: # TODO: both are hardcoded to just put int: 16
-            ir += f"%{node.name} = alloca {node.typ.to_llvm()}, align 8" # TODO: this would only work for i64s, just testing
-            ir += f"\nstore {node.typ.to_llvm()} 16, {node.typ.to_llvm()}* %{node.name}, align 8"
+            ir += f"%{node.real_name} = alloca {node.typ.to_llvm()}, align 8" # TODO: this would only work for i64s, just testing
+            ir += f"\nstore {node.typ.to_llvm()} 16, {node.typ.to_llvm()}* %{node.real_name}, align 8"
         else:
-            ir += f"%{node.name} = add {node.typ.to_llvm()} 16, 0"
+            ir += f"%{node.real_name} = add {node.typ.to_llvm()} 16, 0"
             
         return ir