diff --git a/Nub.Lang/Nub.Lang/Backend/Custom/ExpressionGenerator.cs b/Nub.Lang/Nub.Lang/Backend/Custom/ExpressionGenerator.cs deleted file mode 100644 index 0be4de6..0000000 --- a/Nub.Lang/Nub.Lang/Backend/Custom/ExpressionGenerator.cs +++ /dev/null @@ -1,306 +0,0 @@ -using System.Text; -using Nub.Lang.Frontend.Parsing; - -namespace Nub.Lang.Backend.Custom; - -public class ExpressionGenerator -{ - private readonly StringBuilder _builder; - private readonly SymbolTable _symbolTable; - - public ExpressionGenerator(SymbolTable symbolTable, StringBuilder builder) - { - _symbolTable = symbolTable; - _builder = builder; - } - - public void GenerateExpression(ExpressionNode expression, LocalFunc func) - { - switch (expression) - { - case BinaryExpressionNode binaryExpression: - GenerateBinaryExpression(binaryExpression, func); - break; - case FuncCallExpressionNode funcCallExpression: - GenerateFuncCall(funcCallExpression.FuncCall, func); - break; - case IdentifierNode identifier: - GenerateIdentifier(identifier, func); - break; - case LiteralNode literal: - GenerateLiteral(literal); - break; - case SyscallExpressionNode syscallExpression: - GenerateSyscall(syscallExpression.Syscall, func); - break; - default: - throw new ArgumentOutOfRangeException(nameof(expression)); - } - } - - private void GenerateBinaryExpression(BinaryExpressionNode binaryExpression, LocalFunc func) - { - GenerateExpression(binaryExpression.Left, func); - _builder.AppendLine(" push rax"); - GenerateExpression(binaryExpression.Right, func); - _builder.AppendLine(" mov rbx, rax"); - _builder.AppendLine(" pop rax"); - - switch (binaryExpression.Operator) - { - case BinaryExpressionOperator.Equal: - GenerateComparison(binaryExpression.Left.Type); - _builder.AppendLine(" sete al"); - _builder.AppendLine(" movzx rax, al"); - break; - case BinaryExpressionOperator.NotEqual: - GenerateComparison(binaryExpression.Left.Type); - _builder.AppendLine(" setne al"); - _builder.AppendLine(" movzx rax, al"); - break; - case BinaryExpressionOperator.GreaterThan: - GenerateComparison(binaryExpression.Left.Type); - _builder.AppendLine(" setg al"); - _builder.AppendLine(" movzx rax, al"); - break; - case BinaryExpressionOperator.GreaterThanOrEqual: - GenerateComparison(binaryExpression.Left.Type); - _builder.AppendLine(" setge al"); - _builder.AppendLine(" movzx rax, al"); - break; - case BinaryExpressionOperator.LessThan: - GenerateComparison(binaryExpression.Left.Type); - _builder.AppendLine(" setl al"); - _builder.AppendLine(" movzx rax, al"); - break; - case BinaryExpressionOperator.LessThanOrEqual: - GenerateComparison(binaryExpression.Left.Type); - _builder.AppendLine(" setle al"); - _builder.AppendLine(" movzx rax, al"); - break; - case BinaryExpressionOperator.Plus: - GenerateBinaryAddition(binaryExpression.Left.Type); - break; - case BinaryExpressionOperator.Minus: - GenerateBinarySubtraction(binaryExpression.Left.Type); - break; - case BinaryExpressionOperator.Multiply: - GenerateBinaryMultiplication(binaryExpression.Left.Type); - break; - case BinaryExpressionOperator.Divide: - GenerateBinaryDivision(binaryExpression.Left.Type); - break; - default: - throw new ArgumentOutOfRangeException(); - } - } - - private void GenerateComparison(Type type) - { - switch (type) - { - case DelegateType: - throw new NotSupportedException($"Comparison on type {type.GetType().Name} is not supported"); - break; - case PrimitiveType: - _builder.AppendLine(" cmp rax, rax"); - break; - case StringType: - _builder.AppendLine(" mov rdi, rax"); - _builder.AppendLine(" mov rsi, rbx"); - _builder.AppendLine(" call strcmp"); - break; - default: - throw new ArgumentOutOfRangeException(nameof(type)); - } - } - - private void GenerateBinaryAddition(Type type) - { - if (type is not PrimitiveType primitiveType) - { - throw new InvalidOperationException("Addition can only be done on primitive types"); - } - - switch (primitiveType.Kind) - { - case PrimitiveTypeKind.Int64: - _builder.AppendLine(" add rax, rbx"); - break; - case PrimitiveTypeKind.Int32: - _builder.AppendLine(" add eax, ebx"); - break; - default: - throw new InvalidOperationException($"Invalid type {primitiveType.Kind}"); - } - } - - private void GenerateBinarySubtraction(Type type) - { - if (type is not PrimitiveType primitiveType) - { - throw new InvalidOperationException("Subtraction can only be done on primitive types"); - } - - switch (primitiveType.Kind) - { - case PrimitiveTypeKind.Int64: - _builder.AppendLine(" sub rax, rbx"); - break; - case PrimitiveTypeKind.Int32: - _builder.AppendLine(" sub eax, ebx"); - break; - default: - throw new InvalidOperationException($"Invalid type {primitiveType.Kind}"); - } - } - - private void GenerateBinaryMultiplication(Type type) - { - if (type is not PrimitiveType primitiveType) - { - throw new InvalidOperationException("Multiplication can only be done on primitive types"); - } - - switch (primitiveType.Kind) - { - case PrimitiveTypeKind.Int64: - _builder.AppendLine(" imul rbx"); - break; - case PrimitiveTypeKind.Int32: - _builder.AppendLine(" imul ebx"); - break; - default: - throw new InvalidOperationException($"Invalid type {primitiveType.Kind}"); - } - } - - private void GenerateBinaryDivision(Type type) - { - if (type is not PrimitiveType primitiveType) - { - throw new InvalidOperationException("Division can only be done on primitive types"); - } - - switch (primitiveType.Kind) - { - case PrimitiveTypeKind.Int64: - _builder.AppendLine(" cqo"); - _builder.AppendLine(" idiv rbx"); - break; - case PrimitiveTypeKind.Int32: - _builder.AppendLine(" cdq"); - _builder.AppendLine(" idiv ebx"); - break; - default: - throw new InvalidOperationException($"Invalid type {primitiveType.Kind}"); - } - } - - private void GenerateIdentifier(IdentifierNode identifier, LocalFunc func) - { - var variable = func.ResolveVariable(identifier.Identifier); - - switch (variable) - { - case GlobalVariable globalVariable: - _builder.AppendLine($" mov rax, [{globalVariable.Identifier}]"); - break; - case LocalVariable localVariable: - { - _builder.AppendLine($" mov rax, [rbp - {localVariable.Offset}]"); - break; - } - default: - { - throw new ArgumentOutOfRangeException(nameof(variable)); - } - } - } - - private void GenerateLiteral(LiteralNode literal) - { - switch (literal.Type) - { - case DelegateType: - { - throw new NotImplementedException(); - break; - } - case StringType: - { - var ident = _symbolTable.LabelFactory.Create(); - _symbolTable.DefineString(ident, literal.Literal); - _builder.AppendLine($" mov rax, {ident}"); - break; - } - case PrimitiveType primitive: - { - switch (primitive.Kind) - { - case PrimitiveTypeKind.Bool: - _builder.AppendLine($" mov rax, {(bool.Parse(literal.Literal) ? "1" : "0")}"); - break; - case PrimitiveTypeKind.Char: - _builder.AppendLine($" mov rax, '{literal.Literal}'"); - break; - case PrimitiveTypeKind.Int64: - _builder.AppendLine($" mov rax, {literal.Literal}"); - break; - case PrimitiveTypeKind.Int32: - _builder.AppendLine($" mov rax, {literal.Literal}"); - break; - default: - throw new Exception("Cannot convert literal to string"); - } - break; - } - default: - throw new ArgumentOutOfRangeException(); - } - } - - public void GenerateFuncCall(FuncCall funcCall, LocalFunc func) - { - var symbol = _symbolTable.ResolveFunc(funcCall.Name, funcCall.Parameters.Select(p => p.Type).ToList()); - string[] registers = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"]; - - for (var i = funcCall.Parameters.Count - 1; i >= 0; i--) - { - GenerateExpression(funcCall.Parameters.ElementAt(i), func); - _builder.AppendLine(" push rax"); - } - - var registerParameters = Math.Min(registers.Length, funcCall.Parameters.Count); - var stackParameters = funcCall.Parameters.Count - registerParameters; - - for (var i = 0; i < registerParameters; i++) - { - _builder.AppendLine($" pop {registers[i]}"); - } - - _builder.AppendLine($" call {symbol.StartLabel}"); - if (stackParameters != 0) - { - _builder.AppendLine($" add rsp, {stackParameters}"); - } - } - - public void GenerateSyscall(Syscall syscall, LocalFunc func) - { - string[] registers = ["rax", "rdi", "rsi", "rdx", "r10", "r8", "r9"]; - - foreach (var parameter in syscall.Parameters) - { - GenerateExpression(parameter, func); - _builder.AppendLine(" push rax"); - } - - for (var i = syscall.Parameters.Count - 1; i >= 0; i--) - { - _builder.AppendLine($" pop {registers[i]}"); - } - - _builder.AppendLine(" syscall"); - } -} \ No newline at end of file diff --git a/Nub.Lang/Nub.Lang/Backend/Custom/FuncGenerator.cs b/Nub.Lang/Nub.Lang/Backend/Custom/FuncGenerator.cs deleted file mode 100644 index 8acdfa4..0000000 --- a/Nub.Lang/Nub.Lang/Backend/Custom/FuncGenerator.cs +++ /dev/null @@ -1,146 +0,0 @@ -using System.Text; -using Nub.Lang.Frontend.Parsing; - -namespace Nub.Lang.Backend.Custom; - -public class FuncGenerator -{ - private readonly SymbolTable _symbolTable; - private readonly ExpressionGenerator _expressionGenerator; - private readonly StringBuilder _builder; - - public FuncGenerator(SymbolTable symbolTable, StringBuilder builder, ExpressionGenerator expressionGenerator) - { - _symbolTable = symbolTable; - _builder = builder; - _expressionGenerator = expressionGenerator; - } - - public string GenerateFuncDefinition(LocalFuncDefinitionNode node) - { - var func = _symbolTable.ResolveLocalFunc(node.Name, node.Parameters.Select(p => p.Type).ToList()); - - _builder.AppendLine($"; {node.ToString()}"); - _builder.AppendLine($"{func.StartLabel}:"); - _builder.AppendLine(" ; Set up stack frame"); - _builder.AppendLine(" push rbp"); - _builder.AppendLine(" mov rbp, rsp"); - _builder.AppendLine($" sub rsp, {func.StackAllocation}"); - - string[] registers = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"]; - - _builder.AppendLine(" ; Body"); - for (var i = 0; i < func.Parameters.Count; i++) - { - var parameter = func.ResolveLocalVariable(func.Parameters.ElementAt(i).Name); - if (i < registers.Length) - { - _builder.AppendLine($" mov [rbp - {parameter.Offset}], {registers[i]}"); - } - else - { - var stackOffset = 16 + (i - registers.Length) * 8; - _builder.AppendLine($" mov rax, [rbp + {stackOffset}]"); - _builder.AppendLine($" mov [rbp - {parameter.Offset}], rax"); - } - } - - GenerateBlock(node.Body, func); - - _builder.AppendLine($"{func.EndLabel}:"); - _builder.AppendLine(" ; Clean up stack frame"); - _builder.AppendLine(" mov rsp, rbp"); - _builder.AppendLine(" pop rbp"); - _builder.AppendLine(" ret"); - - var result = _builder.ToString(); - _builder.Clear(); - return result; - } - - private void GenerateBlock(BlockNode block, LocalFunc func) - { - foreach (var statement in block.Statements) - { - GenerateStatement(statement, func); - } - } - - private void GenerateStatement(StatementNode statement, LocalFunc func) - { - switch (statement) - { - case FuncCallStatementNode funcCallStatement: - _expressionGenerator.GenerateFuncCall(funcCallStatement.FuncCall, func); - break; - case IfNode ifStatement: - GenerateIf(ifStatement, func); - break; - case ReturnNode @return: - GenerateReturn(@return, func); - break; - case SyscallStatementNode syscallStatement: - _expressionGenerator.GenerateSyscall(syscallStatement.Syscall, func); - break; - case VariableAssignmentNode variableAssignment: - GenerateVariableAssignment(variableAssignment, func); - break; - case VariableReassignmentNode variableReassignment: - GenerateVariableReassignment(variableReassignment, func); - break; - default: - throw new ArgumentOutOfRangeException(nameof(statement)); - } - } - - private void GenerateIf(IfNode ifStatement, LocalFunc func) - { - var endLabel = _symbolTable.LabelFactory.Create(); - GenerateIf(ifStatement, endLabel, func); - _builder.AppendLine($"{endLabel}:"); - } - - private void GenerateIf(IfNode ifStatement, string endLabel, LocalFunc func) - { - var nextLabel = _symbolTable.LabelFactory.Create(); - _expressionGenerator.GenerateExpression(ifStatement.Condition, func); - _builder.AppendLine(" cmp rax, 0"); - _builder.AppendLine($" je {nextLabel}"); - GenerateBlock(ifStatement.Body, func); - _builder.AppendLine($" jmp {endLabel}"); - _builder.AppendLine($"{nextLabel}:"); - - if (ifStatement.Else.HasValue) - { - ifStatement.Else.Value.Match - ( - elseIfStatement => GenerateIf(elseIfStatement, endLabel, func), - elseStatement => GenerateBlock(elseStatement, func) - ); - } - } - - private void GenerateReturn(ReturnNode @return, LocalFunc func) - { - if (@return.Value.HasValue) - { - _expressionGenerator.GenerateExpression(@return.Value.Value, func); - } - - _builder.AppendLine($" jmp {func.EndLabel}"); - } - - private void GenerateVariableAssignment(VariableAssignmentNode variableAssignment, LocalFunc func) - { - var variable = func.ResolveLocalVariable(variableAssignment.Name); - _expressionGenerator.GenerateExpression(variableAssignment.Value, func); - _builder.AppendLine($" mov [rbp - {variable.Offset}], rax"); - } - - private void GenerateVariableReassignment(VariableReassignmentNode variableReassignment, LocalFunc func) - { - var variable = func.ResolveLocalVariable(variableReassignment.Name); - _expressionGenerator.GenerateExpression(variableReassignment.Value, func); - _builder.AppendLine($" mov [rbp - {variable.Offset}], rax"); - } -} \ No newline at end of file diff --git a/Nub.Lang/Nub.Lang/Backend/Custom/Generator.cs b/Nub.Lang/Nub.Lang/Backend/Custom/Generator.cs index 99f2ec9..a025e08 100644 --- a/Nub.Lang/Nub.Lang/Backend/Custom/Generator.cs +++ b/Nub.Lang/Nub.Lang/Backend/Custom/Generator.cs @@ -10,16 +10,12 @@ public class Generator private readonly List _definitions; private readonly SymbolTable _symbolTable; private readonly StringBuilder _builder; - private readonly ExpressionGenerator _expressionGenerator; - private readonly FuncGenerator _funcGenerator; public Generator(IReadOnlyCollection definitions) { _definitions = []; _builder = new StringBuilder(); _symbolTable = new SymbolTable(); - _expressionGenerator = new ExpressionGenerator(_symbolTable, _builder); - _funcGenerator = new FuncGenerator(_symbolTable, _builder, _expressionGenerator); foreach (var globalVariableDefinition in definitions.OfType()) { @@ -67,7 +63,7 @@ public class Generator foreach (var globalVariable in _definitions.OfType()) { var symbol = _symbolTable.ResolveGlobalVariable(globalVariable.Name); - _expressionGenerator.GenerateExpression(globalVariable.Value, main); + GenerateExpression(globalVariable.Value, main); _builder.AppendLine($" mov [{symbol.Identifier}], rax"); } @@ -85,7 +81,7 @@ public class Generator foreach (var funcDefinition in _definitions.OfType()) { _builder.AppendLine(); - _builder.AppendLine(_funcGenerator.GenerateFuncDefinition(funcDefinition)); + _builder.AppendLine(GenerateFuncDefinition(funcDefinition)); } _builder.AppendLine(""" @@ -118,4 +114,420 @@ public class Generator return _builder.ToString(); } + + private string GenerateFuncDefinition(LocalFuncDefinitionNode node) + { + var func = _symbolTable.ResolveLocalFunc(node.Name, node.Parameters.Select(p => p.Type).ToList()); + + _builder.AppendLine($"; {node.ToString()}"); + _builder.AppendLine($"{func.StartLabel}:"); + _builder.AppendLine(" ; Set up stack frame"); + _builder.AppendLine(" push rbp"); + _builder.AppendLine(" mov rbp, rsp"); + _builder.AppendLine($" sub rsp, {func.StackAllocation}"); + + string[] registers = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"]; + + _builder.AppendLine(" ; Body"); + for (var i = 0; i < func.Parameters.Count; i++) + { + var parameter = func.ResolveLocalVariable(func.Parameters.ElementAt(i).Name); + if (i < registers.Length) + { + _builder.AppendLine($" mov [rbp - {parameter.Offset}], {registers[i]}"); + } + else + { + var stackOffset = 16 + (i - registers.Length) * 8; + _builder.AppendLine($" mov rax, [rbp + {stackOffset}]"); + _builder.AppendLine($" mov [rbp - {parameter.Offset}], rax"); + } + } + + GenerateBlock(node.Body, func); + + _builder.AppendLine($"{func.EndLabel}:"); + _builder.AppendLine(" ; Clean up stack frame"); + _builder.AppendLine(" mov rsp, rbp"); + _builder.AppendLine(" pop rbp"); + _builder.AppendLine(" ret"); + + var result = _builder.ToString(); + _builder.Clear(); + return result; + } + + private void GenerateBlock(BlockNode block, LocalFunc func) + { + foreach (var statement in block.Statements) + { + GenerateStatement(statement, func); + } + } + + private void GenerateStatement(StatementNode statement, LocalFunc func) + { + switch (statement) + { + case FuncCallStatementNode funcCallStatement: + GenerateFuncCall(funcCallStatement.FuncCall, func); + break; + case IfNode ifStatement: + GenerateIf(ifStatement, func); + break; + case ReturnNode @return: + GenerateReturn(@return, func); + break; + case SyscallStatementNode syscallStatement: + GenerateSyscall(syscallStatement.Syscall, func); + break; + case VariableAssignmentNode variableAssignment: + GenerateVariableAssignment(variableAssignment, func); + break; + case VariableReassignmentNode variableReassignment: + GenerateVariableReassignment(variableReassignment, func); + break; + default: + throw new ArgumentOutOfRangeException(nameof(statement)); + } + } + + private void GenerateIf(IfNode ifStatement, LocalFunc func) + { + var endLabel = _symbolTable.LabelFactory.Create(); + GenerateIf(ifStatement, endLabel, func); + _builder.AppendLine($"{endLabel}:"); + } + + private void GenerateIf(IfNode ifStatement, string endLabel, LocalFunc func) + { + var nextLabel = _symbolTable.LabelFactory.Create(); + GenerateExpression(ifStatement.Condition, func); + _builder.AppendLine(" cmp rax, 0"); + _builder.AppendLine($" je {nextLabel}"); + GenerateBlock(ifStatement.Body, func); + _builder.AppendLine($" jmp {endLabel}"); + _builder.AppendLine($"{nextLabel}:"); + + if (ifStatement.Else.HasValue) + { + ifStatement.Else.Value.Match + ( + elseIfStatement => GenerateIf(elseIfStatement, endLabel, func), + elseStatement => GenerateBlock(elseStatement, func) + ); + } + } + + private void GenerateReturn(ReturnNode @return, LocalFunc func) + { + if (@return.Value.HasValue) + { + GenerateExpression(@return.Value.Value, func); + } + + _builder.AppendLine($" jmp {func.EndLabel}"); + } + + private void GenerateVariableAssignment(VariableAssignmentNode variableAssignment, LocalFunc func) + { + var variable = func.ResolveLocalVariable(variableAssignment.Name); + GenerateExpression(variableAssignment.Value, func); + _builder.AppendLine($" mov [rbp - {variable.Offset}], rax"); + } + + private void GenerateVariableReassignment(VariableReassignmentNode variableReassignment, LocalFunc func) + { + var variable = func.ResolveLocalVariable(variableReassignment.Name); + GenerateExpression(variableReassignment.Value, func); + _builder.AppendLine($" mov [rbp - {variable.Offset}], rax"); + } + + private void GenerateExpression(ExpressionNode expression, LocalFunc func) + { + switch (expression) + { + case BinaryExpressionNode binaryExpression: + GenerateBinaryExpression(binaryExpression, func); + break; + case FuncCallExpressionNode funcCallExpression: + GenerateFuncCall(funcCallExpression.FuncCall, func); + break; + case IdentifierNode identifier: + GenerateIdentifier(identifier, func); + break; + case LiteralNode literal: + GenerateLiteral(literal); + break; + case SyscallExpressionNode syscallExpression: + GenerateSyscall(syscallExpression.Syscall, func); + break; + default: + throw new ArgumentOutOfRangeException(nameof(expression)); + } + } + + private void GenerateBinaryExpression(BinaryExpressionNode binaryExpression, LocalFunc func) + { + GenerateExpression(binaryExpression.Left, func); + _builder.AppendLine(" push rax"); + GenerateExpression(binaryExpression.Right, func); + _builder.AppendLine(" mov rbx, rax"); + _builder.AppendLine(" pop rax"); + + switch (binaryExpression.Operator) + { + case BinaryExpressionOperator.Equal: + GenerateComparison(binaryExpression.Left.Type); + _builder.AppendLine(" sete al"); + _builder.AppendLine(" movzx rax, al"); + break; + case BinaryExpressionOperator.NotEqual: + GenerateComparison(binaryExpression.Left.Type); + _builder.AppendLine(" setne al"); + _builder.AppendLine(" movzx rax, al"); + break; + case BinaryExpressionOperator.GreaterThan: + GenerateComparison(binaryExpression.Left.Type); + _builder.AppendLine(" setg al"); + _builder.AppendLine(" movzx rax, al"); + break; + case BinaryExpressionOperator.GreaterThanOrEqual: + GenerateComparison(binaryExpression.Left.Type); + _builder.AppendLine(" setge al"); + _builder.AppendLine(" movzx rax, al"); + break; + case BinaryExpressionOperator.LessThan: + GenerateComparison(binaryExpression.Left.Type); + _builder.AppendLine(" setl al"); + _builder.AppendLine(" movzx rax, al"); + break; + case BinaryExpressionOperator.LessThanOrEqual: + GenerateComparison(binaryExpression.Left.Type); + _builder.AppendLine(" setle al"); + _builder.AppendLine(" movzx rax, al"); + break; + case BinaryExpressionOperator.Plus: + GenerateBinaryAddition(binaryExpression.Left.Type); + break; + case BinaryExpressionOperator.Minus: + GenerateBinarySubtraction(binaryExpression.Left.Type); + break; + case BinaryExpressionOperator.Multiply: + GenerateBinaryMultiplication(binaryExpression.Left.Type); + break; + case BinaryExpressionOperator.Divide: + GenerateBinaryDivision(binaryExpression.Left.Type); + break; + default: + throw new ArgumentOutOfRangeException(nameof(binaryExpression.Operator)); + } + } + + private void GenerateComparison(Type type) + { + switch (type) + { + case DelegateType: + throw new NotSupportedException($"Comparison on type {type.GetType().Name} is not supported"); + case PrimitiveType: + _builder.AppendLine(" cmp rax, rax"); + break; + case StringType: + _builder.AppendLine(" mov rdi, rax"); + _builder.AppendLine(" mov rsi, rbx"); + _builder.AppendLine(" call strcmp"); + break; + default: + throw new ArgumentOutOfRangeException(nameof(type)); + } + } + + private void GenerateBinaryAddition(Type type) + { + if (type is not PrimitiveType primitiveType) + { + throw new InvalidOperationException("Addition can only be done on primitive types"); + } + + switch (primitiveType.Kind) + { + case PrimitiveTypeKind.Int64: + _builder.AppendLine(" add rax, rbx"); + break; + case PrimitiveTypeKind.Int32: + _builder.AppendLine(" add eax, ebx"); + break; + default: + throw new InvalidOperationException($"Invalid type {primitiveType.Kind}"); + } + } + + private void GenerateBinarySubtraction(Type type) + { + if (type is not PrimitiveType primitiveType) + { + throw new InvalidOperationException("Subtraction can only be done on primitive types"); + } + + switch (primitiveType.Kind) + { + case PrimitiveTypeKind.Int64: + _builder.AppendLine(" sub rax, rbx"); + break; + case PrimitiveTypeKind.Int32: + _builder.AppendLine(" sub eax, ebx"); + break; + default: + throw new InvalidOperationException($"Invalid type {primitiveType.Kind}"); + } + } + + private void GenerateBinaryMultiplication(Type type) + { + if (type is not PrimitiveType primitiveType) + { + throw new InvalidOperationException("Multiplication can only be done on primitive types"); + } + + switch (primitiveType.Kind) + { + case PrimitiveTypeKind.Int64: + _builder.AppendLine(" imul rbx"); + break; + case PrimitiveTypeKind.Int32: + _builder.AppendLine(" imul ebx"); + break; + default: + throw new InvalidOperationException($"Invalid type {primitiveType.Kind}"); + } + } + + private void GenerateBinaryDivision(Type type) + { + if (type is not PrimitiveType primitiveType) + { + throw new InvalidOperationException("Division can only be done on primitive types"); + } + + switch (primitiveType.Kind) + { + case PrimitiveTypeKind.Int64: + _builder.AppendLine(" cqo"); + _builder.AppendLine(" idiv rbx"); + break; + case PrimitiveTypeKind.Int32: + _builder.AppendLine(" cdq"); + _builder.AppendLine(" idiv ebx"); + break; + default: + throw new InvalidOperationException($"Invalid type {primitiveType.Kind}"); + } + } + + private void GenerateIdentifier(IdentifierNode identifier, LocalFunc func) + { + var variable = func.ResolveVariable(identifier.Identifier); + + switch (variable) + { + case GlobalVariable globalVariable: + _builder.AppendLine($" mov rax, [{globalVariable.Identifier}]"); + break; + case LocalVariable localVariable: + { + _builder.AppendLine($" mov rax, [rbp - {localVariable.Offset}]"); + break; + } + default: + { + throw new ArgumentOutOfRangeException(nameof(variable)); + } + } + } + + private void GenerateLiteral(LiteralNode literal) + { + switch (literal.Type) + { + case DelegateType: + { + throw new NotImplementedException(); + } + case StringType: + { + var ident = _symbolTable.LabelFactory.Create(); + _symbolTable.DefineString(ident, literal.Literal); + _builder.AppendLine($" mov rax, {ident}"); + break; + } + case PrimitiveType primitive: + { + switch (primitive.Kind) + { + case PrimitiveTypeKind.Bool: + _builder.AppendLine($" mov rax, {(bool.Parse(literal.Literal) ? "1" : "0")}"); + break; + case PrimitiveTypeKind.Char: + _builder.AppendLine($" mov rax, '{literal.Literal}'"); + break; + case PrimitiveTypeKind.Int64: + _builder.AppendLine($" mov rax, {literal.Literal}"); + break; + case PrimitiveTypeKind.Int32: + _builder.AppendLine($" mov rax, {literal.Literal}"); + break; + default: + throw new Exception("Cannot convert literal to string"); + } + break; + } + default: + throw new ArgumentOutOfRangeException(); + } + } + + private void GenerateFuncCall(FuncCall funcCall, LocalFunc func) + { + var symbol = _symbolTable.ResolveFunc(funcCall.Name, funcCall.Parameters.Select(p => p.Type).ToList()); + string[] registers = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"]; + + for (var i = funcCall.Parameters.Count - 1; i >= 0; i--) + { + GenerateExpression(funcCall.Parameters.ElementAt(i), func); + _builder.AppendLine(" push rax"); + } + + var registerParameters = Math.Min(registers.Length, funcCall.Parameters.Count); + var stackParameters = funcCall.Parameters.Count - registerParameters; + + for (var i = 0; i < registerParameters; i++) + { + _builder.AppendLine($" pop {registers[i]}"); + } + + _builder.AppendLine($" call {symbol.StartLabel}"); + if (stackParameters != 0) + { + _builder.AppendLine($" add rsp, {stackParameters}"); + } + } + + private void GenerateSyscall(Syscall syscall, LocalFunc func) + { + string[] registers = ["rax", "rdi", "rsi", "rdx", "r10", "r8", "r9"]; + + foreach (var parameter in syscall.Parameters) + { + GenerateExpression(parameter, func); + _builder.AppendLine(" push rax"); + } + + for (var i = syscall.Parameters.Count - 1; i >= 0; i--) + { + _builder.AppendLine($" pop {registers[i]}"); + } + + _builder.AppendLine(" syscall"); + } } \ No newline at end of file