浏览代码

fix function overloading, more codegen

Johan Rong 4 天之前
父节点
当前提交
36d0044080
共有 6 个文件被更改,包括 137 次插入 和 96 次删除
  1. 9 4
      src/zelkelc/__main__.py
  2. 4 4
      src/zelkelc/ast/nodes.py
  3. 13 16
      src/zelkelc/ast/parser.py
  4. 9 4
      src/zelkelc/ast/types.py
  5. 21 19
      src/zelkelc/codegen/codegen.py
  6. 81 49
      src/zelkelc/validator/scope.py

+ 9 - 4
src/zelkelc/__main__.py

@@ -7,13 +7,18 @@ import rich
 
 source = """
 class String {
-    value: str
+    val value: i64
+    
+    fn test() -> void {
+        return
+    }
+    
 }
 
-fn main() -> i64 {
+fn main() -> void {
     val a: i64 = 1
-    val test: i64 = 74 + 123 * (2+3 * 4)
-    return 0
+    val test: i64 = a + 1
+    return
 }
 """
 

+ 4 - 4
src/zelkelc/ast/nodes.py

@@ -8,13 +8,13 @@ class ClassDeclaration:
     name: str
     members: list[ValueDeclaration]
     methods: list[FunctionDeclaration]
-    real_name: str
+    irname: str
 
 @dataclass
 class StructDeclaration:
     name: str
     members: list[MemberDeclaration]
-    real_name: str
+    irname: str
 
 @dataclass
 class MemberDeclaration:
@@ -29,7 +29,7 @@ class ValueDeclaration:
     mutable: bool
     typ: values.Value
     expr: Expression
-    real_name: str
+    irname: str
     
 @dataclass
 class FunctionDeclaration:
@@ -37,7 +37,7 @@ class FunctionDeclaration:
     typ: values.Value
     args: dict[str, values.Value]
     body: list[Node]
-    real_name: str
+    irname: str
     
 @dataclass
 class ReturnStatement:

+ 13 - 16
src/zelkelc/ast/parser.py

@@ -101,7 +101,7 @@ class Parser:
         return types.StructDeclaration(
             name,
             members,
-            real_name = f"{path}.s_{name}"
+            irname = f"{path}.s_{name}"
         )
     
     def parse_member_declaration(self, mutable: bool, member_idx: int) -> types.MemberDeclaration:
@@ -155,7 +155,7 @@ class Parser:
             name,
             members,
             methods,
-            real_name = f"{path}.c_{name}"
+            irname = f"{path}.c_{name}"
         )
     
     def parse_function_declaration(self, path: str) -> types.FunctionDeclaration:
@@ -215,29 +215,25 @@ class Parser:
         
         self.expect(token.RBrace())
         
-        real_name = f"{path}.f_{name}_{typ}"
+        irname = f"{path}.f_{name}_{typ}"
         if name == "main":
-            real_name = "main"
+            irname = "main"
         
         return types.FunctionDeclaration(
             name = name,
             typ = typ,
             args = args,
             body = body,
-            real_name = real_name
+            irname = irname
         )
     
     def parse_return(self) -> types.ReturnStatement:
         self.expect(token.Identifier("return"))
         
-        # TODO: if there is an expression then check for add it?
-    
         expr: Optional[types.Expression] = None    
         if not self.current(token.RBrace()):
             expr = self.parse_expression()
 
-        print(expr)
-        
         return types.ReturnStatement(
             expr
         )
@@ -262,7 +258,7 @@ class Parser:
             mutable,
             typ,
             expr,
-            real_name = f"v_{self.cursor}_{name}"
+            irname = f"v_{self.cursor}_{name}"
         )
     
     def parse_expression(self) -> types.Expression:
@@ -283,7 +279,7 @@ class Parser:
 
             right = self.parse_binary_expression(precedence + 1)
 
-            left = types.BinaryExpression(left, right, op)
+            left = types.BinaryExpression(left, right, op, left.typ)
 
         return left
 
@@ -295,7 +291,7 @@ class Parser:
                 print(f"Invalid unary operator: {op}")
                 exit(1)
             operand = self.parse_unary_expression()
-            return types.UnaryExpression(operand, op)
+            return types.UnaryExpression(operand, op, operand.typ)
 
         return self.parse_primary_expression()
 
@@ -315,17 +311,17 @@ class Parser:
                         args.append(self.parse_expression())
                     
                     self.expect(token.RParen())
-                    return types.PrimaryExpression(types.FunctionCall(t.value, args))
+                    return types.PrimaryExpression(types.FunctionCall(t.value, args, None), types.FunctionCall)
                 else:
-                    return types.PrimaryExpression(types.VariableRef(t.value))
+                    return types.PrimaryExpression(types.VariableRef(t.value, None), types.VariableRef)
 
             case token.Integer():
                 self.cursor += 1
-                return types.PrimaryExpression(types.Integer64(t.value))
+                return types.PrimaryExpression(types.Integer64(t.value), types.Integer64)
 
             case token.String():
                 self.cursor += 1
-                return types.PrimaryExpression(types.String(t.value))
+                return types.PrimaryExpression(types.String(t.value), types.String)
 
             case token.LParen():
                 self.expect(token.LParen())
@@ -345,4 +341,5 @@ class Parser:
             "+": 5, "-": 5,
             "*": 6, "/": 6, "%": 6,
         }
+        
         return table.get(op, 0)

+ 9 - 4
src/zelkelc/ast/types.py

@@ -8,13 +8,13 @@ class ClassDeclaration:
     name: str
     members: list[ValueDeclaration]
     methods: list[FunctionDeclaration]
-    real_name: str
+    irname: str
 
 @dataclass
 class StructDeclaration:
     name: str
     members: list[MemberDeclaration]
-    real_name: str
+    irname: str
 
 @dataclass
 class MemberDeclaration:
@@ -29,7 +29,7 @@ class ValueDeclaration:
     mutable: bool
     typ: Value
     expr: Expression
-    real_name: str
+    irname: str
     
 @dataclass
 class FunctionDeclaration:
@@ -37,7 +37,7 @@ class FunctionDeclaration:
     typ: Value
     args: dict[str, Value]
     body: list[Node]
-    real_name: str
+    irname: str
     
 @dataclass
 class ReturnStatement:
@@ -50,15 +50,18 @@ class BinaryExpression:
     left: Expression
     right: Expression
     op: str
+    typ: Value
 
 @dataclass
 class UnaryExpression:
     expr: Expression
     sign: str
+    typ: Value
 
 @dataclass
 class PrimaryExpression:
     value: Value
+    typ: Value
 
 Expression = BinaryExpression | UnaryExpression | PrimaryExpression
 
@@ -92,6 +95,7 @@ class Void:
 @dataclass
 class VariableRef:
     name: str
+    irname: str
     
     def to_llvm() -> str:
         print("Cannot convert Variable to llvm ir")
@@ -100,6 +104,7 @@ class VariableRef:
 @dataclass
 class FunctionCall:
     name: str
+    irname: str
     args: list[Expression]
 
 @dataclass

+ 21 - 19
src/zelkelc/codegen/codegen.py

@@ -40,14 +40,14 @@ class Codegen:
         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 + " }"
+        self.ir.structs += f"\n%{node.irname} = type " + "{ " + members_str + " }"
 
     def gen_class_declaration(self, node: types.ClassDeclaration):
         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 + " }"
+        self.ir.structs += f"\n%{node.irname} = type " + "{ " + members_str + " }"
         
         for func in node.methods:
             self.ir.struct_functions += self.gen_function_declaration(func)
@@ -57,7 +57,7 @@ class Codegen:
         for i, (name, typ) in enumerate(node.args.items()):
             args_str += f"{", " if i != 0 else ""}{typ.to_llvm()} %{name}"
             
-        ir = f"\ndefine {str(node.typ.to_llvm())} @{node.real_name}({args_str}) " + "{"
+        ir = f"\ndefine {str(node.typ.to_llvm())} @{node.irname}({args_str}) " + "{"
         ir += "\nentry:"
         
         for child_node in node.body:
@@ -78,29 +78,27 @@ class Codegen:
         match node.typ:
             case types.Integer64:
                 if node.mutable == True:
-                    ir += f"\n%{node.real_name} = alloca i64, align 8" # TODO: this would only work for i64s, just testing
-                    ir += f"\nstore i64 %{count}, i64* %{node.real_name}, align 8"
+                    ir += f"\n%{node.irname} = alloca i64, align 8" # TODO: this would only work for i64s, just testing
+                    ir += f"\nstore i64 %{count}, i64* %{node.irname}, align 8"
                 else:
-                    ir += f"\n%{node.real_name} = add i64 %{count}, 0" 
+                    ir += f"\n%{node.irname} = add i64 %{count}, 0"
             case _:
                 print(f"gen_value_declaration() for {type(node.typ)} is unimplemented")
                 exit(1)
             
         return ir
     
-    def gen_expression(self, node: types.Expression) -> tuple[int, str]:
+    def gen_expression(self, node: types.Expression) -> tuple[str, str]:
         ir = ""
         
         match type(node):
             case types.BinaryExpression:
-                left_count, left = self.gen_expression(node.left)
-                right_count, right = self.gen_expression(node.right)
+                left_irname, left = self.gen_expression(node.left)
+                right_irname, right = self.gen_expression(node.right)
                 
                 ir += left + right
-                        
-                #match type(node.left.): # TODO: need to know the value type of the expresison here...
-                #    case types.Integer64:
-                op = ""          
+                
+                op = ""
                 match node.op:
                     case '+':
                         op = "add"
@@ -115,11 +113,13 @@ class Codegen:
                         print(f"gen_expression() for BinaryExpression for operator '{node.op}' is unimplemented")
                         exit(1)
                         
-                ir += f"\n%{self.temp_counter} = {op} i64 %{left_count}, %{right_count}"
-                self.temp_counter += 1
-                #    case _:
-                #        print(f"gen_expression() for PrimaryExpression for {type(node.value)}")
-                #        exit(1)
+                match node.left.typ:
+                   case types.Integer64:
+                        ir += f"\n%{self.temp_counter} = {op} i64 %{left_irname}, %{right_irname}"
+                        self.temp_counter += 1
+                   case _:
+                       print(f"gen_expression() for BinaryExpression for {node.left.typ}")
+                       exit(1)
             case types.UnaryExpression:
                 print("gen_expression() for UnaryExpression unimplemented")
                 exit(1)
@@ -128,6 +128,8 @@ class Codegen:
                     case types.Integer64:
                         ir += f"\n%{self.temp_counter} = add i64 {node.value.value}, 0"
                         self.temp_counter += 1
+                    case types.VariableRef:
+                        return node.value.irname, ir
                     case _:
                         print(f"gen_expression() for PrimaryExpression for {type(node.value)}")
                         exit(1)
@@ -135,4 +137,4 @@ class Codegen:
                 print(f"Invalid expression types found during codegen: {node}")
                 exit(1)
 
-        return self.temp_counter - 1, ir
+        return str(self.temp_counter - 1), ir

+ 81 - 49
src/zelkelc/validator/scope.py

@@ -12,20 +12,20 @@ class SemanticError:
 @dataclass
 class StructSignature:
     name: str
-    real_name: str
+    irname: str
     members: dict[str, MemberSignature]
 
 @dataclass
 class ClassSignature:
     name: str
-    real_name: str
+    irname: str
     members: dict[str, MemberSignature]
-    methods: dict[str, FunctionSignature]
+    methods: dict[str, list[FunctionSignature]]
 
 @dataclass 
 class FunctionSignature:
     name: str
-    real_name: str
+    irname: str
     static: bool
     typ: types.Value
     args: dict[str, types.Value]
@@ -33,14 +33,14 @@ class FunctionSignature:
 @dataclass
 class ValueSignature:
     name: str
-    real_name: str
+    irname: str
     mutable: bool
     typ: type[types.Integer64] | type[types.String] | type[types.Void]
     
 @dataclass
 class MemberSignature:
     name: str
-    real_name: str
+    irname: str
     mutable: bool
     typ: type[types.Integer64] | type[types.String] | type[types.Void]
     member_idx: int
@@ -57,19 +57,19 @@ class Scope:
     def root() -> Scope:
         return Scope(
             parent=None,
-            classes = {},
-            structs = {},
-            functions = {},
-            values = {},
+            classes={},
+            structs={},
+            functions={},
+            values={},
         )
 
     def child(self) -> Scope:
         return Scope(
-            parent = self,
-            classes = self.classes,
-            structs = self.structs,
-            functions = self.functions,
-            values = {},
+            parent=self,
+            classes=self.classes,
+            structs=self.structs,
+            functions=self.functions,
+            values={},
         )
 
     def resolve_variable(self, name: str) -> Optional[ValueSignature]:
@@ -80,17 +80,27 @@ class Scope:
             current = current.parent
         return None
 
-    def resolve_function(self, scope_checker: ScopeChecker, name: str, args: list[types.Value]) -> list[Optional[FunctionSignature]]:
+    def resolve_function(self, scope_checker: ScopeChecker, name: str, args: list[types.Expression]) -> Optional[FunctionSignature]:
         current: Optional[Scope] = self
         while current is not None:
-            if name in current.functions:
-                func = current.functions[name]
-                arg_types = self.expr_args_to_arg_types(scope_checker, args)
+            overloads = current.functions.get(name)
+            if overloads:
+                arg_types = current.expr_args_to_arg_types(scope_checker, args)
                 if arg_types is None:
                     return None
-                
-                if list(func.args.values()) == arg_types:
-                    return func
+
+                return current.resolve_function_by_types(name, arg_types)
+            current = current.parent
+        return None
+
+    def resolve_function_by_types(self, name: str, arg_types: list[types.Value]) -> Optional[FunctionSignature]:
+        current: Optional[Scope] = self
+        while current is not None:
+            overloads = current.functions.get(name)
+            if overloads:
+                for candidate in overloads:
+                    if list(candidate.args.values()) == arg_types:
+                        return candidate
             current = current.parent
         return None
 
@@ -100,11 +110,16 @@ class Scope:
             typ = scope_checker._infer_expression_type(arg, self)
             if typ is None:
                 return None
-            
+
             arg_types.append(typ)
-        
+
         return arg_types
 
+    def _ensure_function_overloads(self, name: str) -> list[FunctionSignature]:
+        if name not in self.functions:
+            self.functions[name] = []
+        return self.functions[name]
+
 class ScopeChecker:
     global_scope: Scope
     errors: list[SemanticError]
@@ -133,7 +148,7 @@ class ScopeChecker:
     def _collect_globals(self, tree: list[types.Node]) -> None:
         for top_level in tree:
             match top_level:
-                case types.StructDeclaration(name=name, real_name=real_name, members=members):
+                case types.StructDeclaration(name=name, irname=irname, members=members):
                     if name in self.global_scope.structs:
                         self._error(f"Struct '{name}' is already declared")
                         continue
@@ -145,7 +160,7 @@ class ScopeChecker:
                             continue
                         member_table[member.name] = MemberSignature(
                             name = member.name,
-                            real_name = f"{real_name}.m_{member.name}",
+                            irname = f"{irname}.m_{member.name}",
                             mutable = member.mutable,
                             typ = member.typ,
                             member_idx = member.real_idx,
@@ -153,11 +168,11 @@ class ScopeChecker:
 
                     self.global_scope.structs[name] = StructSignature(
                         name=name,
-                        real_name=real_name,
+                        irname=irname,
                         members=member_table,
                     )
 
-                case types.ClassDeclaration(name=name, real_name=real_name, members=members, methods=methods):
+                case types.ClassDeclaration(name=name, irname=irname, members=members, methods=methods):
                     if name in self.global_scope.classes:
                         self._error(f"Class '{name}' is already declared")
                         continue
@@ -169,42 +184,52 @@ class ScopeChecker:
                             continue
                         member_table[member.name] = MemberSignature(
                             name = member.name,
-                            real_name = f"{real_name}.m_{member.name}",
+                            irname = f"{irname}.m_{member.name}",
                             mutable = member.mutable,
                             typ = member.typ,
                             member_idx = idx,
                         )
 
-                    method_table: dict[str, FunctionSignature] = {}
+                    method_table: dict[str, list[FunctionSignature]] = {}
                     for method in methods:
-                        if method.name in method_table:
-                            self._error(f"Duplicate method '{method.name}' in class '{name}'")
-                            continue
-                        method_table[method.name] = FunctionSignature(
+                        signature = FunctionSignature(
                             name = method.name,
-                            real_name = method.real_name,
+                            irname = method.irname,
                             static = False,
                             typ = method.typ,
                             args = method.args,
                         )
-                        
-                        if 
 
+                        overloads = method_table.setdefault(method.name, [])
+                        has_duplicate_signature = any(
+                            list(existing.args.values()) == list(signature.args.values())
+                            for existing in overloads
+                        )
+                        if has_duplicate_signature:
+                            self._error(
+                                f"Duplicate method '{method.name}' in class '{name}' "
+                                f"with same argument signature"
+                            )
+                            continue
+
+                        overloads.append(signature)
+                        
                     self.global_scope.classes[name] = ClassSignature(
                         name = name,
-                        real_name = real_name,
+                        irname = irname,
                         members = member_table,
                         methods = method_table,
                     )
 
-                case types.FunctionDeclaration(name, typ, args, _, real_name):
-                    existing = self.global_scope.resolve_function(self, name, list(args.values()))
+                case types.FunctionDeclaration(name, typ, args, _, irname):
+                    existing = self.global_scope.resolve_function_by_types(name, list(args.values()))
                     if not existing is None:
                         self._error(f"Function '{name}' is already defined with following signature '{existing}'")
+                        continue
 
-                    self.global_scope.functions[name].append(FunctionSignature(
+                    self.global_scope._ensure_function_overloads(name).append(FunctionSignature(
                         name = name,
-                        real_name = real_name,
+                        irname = irname,
                         static = True,
                         typ = typ,
                         args = args,
@@ -222,7 +247,7 @@ class ScopeChecker:
                 continue
             function_scope.values[arg_name] = ValueSignature(
                 name = arg_name,
-                real_name = arg_name,
+                irname = arg_name,
                 mutable = False,
                 typ = arg_type,
             )
@@ -245,7 +270,7 @@ class ScopeChecker:
 
                     function_scope.values[child.name] = ValueSignature(
                         name = child.name,
-                        real_name = child.real_name,
+                        irname = child.irname,
                         mutable = child.mutable,
                         typ = child.typ,
                     )
@@ -272,16 +297,17 @@ class ScopeChecker:
                         )
 
                 case types.FunctionDeclaration():
-                    if child.name in function_scope.functions:
+                    existing_nested = function_scope.resolve_function_by_types(child.name, list(child.args.values()))
+                    if existing_nested is not None:
                         self._error(f"Nested function '{child.name}' is already defined in '{fn.name}'")
                     else:
-                        function_scope.functions[child.name] = FunctionSignature(
+                        function_scope._ensure_function_overloads(child.name).append(FunctionSignature(
                             name = child.name,
-                            real_name = child.real_name,
+                            irname = child.irname,
                             static = True,
                             typ = child.typ,
                             args = child.args,
-                        )
+                        ))
                     self._check_function(child, function_scope)
 
                 case _:
@@ -301,15 +327,21 @@ class ScopeChecker:
                 if signature is None:
                     self._error(f"Unknown variable '{name}'")
                     return None
+                
+                expr.value.irname = signature.irname
                 return signature.typ
             case types.PrimaryExpression(types.FunctionCall(name, args)):
                 arg_types = active_scope.expr_args_to_arg_types(self, args)
                 if arg_types is None:
                     self._error(f"Could not get argument types from function call")
-                signature = active_scope.resolve_function(self, name, arg_types)
+                    return None
+
+                signature = active_scope.resolve_function_by_types(name, arg_types)
                 if signature is None:
                     self._error(f"Unknown function '{name}' with given argument signature")
                     return None
+                
+                expr.value.irname = signature.irname
                 return signature.typ
             case types.UnaryExpression(expr=inner_expr, sign=sign):
                 inner_type = self._infer_expression_type(inner_expr, active_scope)