This commit is contained in:
nub31
2025-07-06 23:22:51 +02:00
parent 10a5b2ea33
commit cc3eab8a1b
4 changed files with 737 additions and 715 deletions

View File

@@ -0,0 +1,158 @@
using System.Diagnostics;
using NubLang.Syntax.Binding.Node;
namespace NubLang.Generation.QBE;
public partial class QBEGenerator
{
private void EmitStatement(BoundStatement statement)
{
_writer.WriteDebugLocation(statement);
switch (statement)
{
case BoundAssignment assignment:
EmitAssignment(assignment);
break;
case BoundBreak:
EmitBreak();
break;
case BoundContinue:
EmitContinue();
break;
case BoundIf ifStatement:
EmitIf(ifStatement);
break;
case BoundReturn @return:
EmitReturn(@return);
break;
case BoundStatementExpression statementExpression:
EmitExpression(statementExpression.Expression);
break;
case BoundVariableDeclaration variableDeclaration:
EmitVariableDeclaration(variableDeclaration);
break;
case BoundWhile whileStatement:
EmitWhile(whileStatement);
break;
default:
throw new ArgumentOutOfRangeException(nameof(statement));
}
}
private void EmitAssignment(BoundAssignment assignment)
{
var destination = EmitExpression(assignment.Target);
Debug.Assert(destination.Kind == ValKind.Pointer);
EmitCopyIntoOrInitialize(assignment.Value, destination.Name);
}
private void EmitBlock(BoundBlock block, List<Variable>? variables = null)
{
_variableScopes.Push(_variables.Count);
if (variables != null)
{
foreach (var variable in variables)
{
_variables.Push(variable);
}
}
foreach (var statement in block.Statements.Where(_ => _codeIsReachable))
{
EmitStatement(statement);
}
var count = _variableScopes.Pop();
while (_variableScopes.Count > count)
{
_variableScopes.Pop();
}
_codeIsReachable = true;
}
private void EmitBreak()
{
_writer.Indented($"jmp {_breakLabels.Peek()}");
_codeIsReachable = false;
}
private void EmitContinue()
{
_writer.Indented($"jmp {_continueLabels.Peek()}");
_codeIsReachable = false;
}
private void EmitIf(BoundIf ifStatement)
{
var trueLabel = LabelName();
var falseLabel = LabelName();
var endLabel = LabelName();
var result = EmitUnwrap(EmitExpression(ifStatement.Condition));
_writer.Indented($"jnz {result}, {trueLabel}, {falseLabel}");
_writer.WriteLine(trueLabel);
EmitBlock(ifStatement.Body);
_writer.Indented($"jmp {endLabel}");
_writer.WriteLine(falseLabel);
if (ifStatement.Else.HasValue)
{
ifStatement.Else.Value.Match
(
elseIfNode => EmitIf(elseIfNode),
elseNode => EmitBlock(elseNode)
);
}
_writer.WriteLine(endLabel);
}
private void EmitReturn(BoundReturn @return)
{
if (@return.Value.HasValue)
{
var result = EmitUnwrap(EmitExpression(@return.Value.Value));
_writer.Indented($"ret {result}");
}
else
{
_writer.Indented("ret");
}
}
private void EmitVariableDeclaration(BoundVariableDeclaration variableDeclaration)
{
var name = $"%{variableDeclaration.Name}";
_writer.Indented($"{name} =l alloc8 8");
if (variableDeclaration.Assignment.HasValue)
{
var value = EmitCreateCopyOrInitialize(variableDeclaration.Assignment.Value);
EmitStore(variableDeclaration.Assignment.Value.Type, value, name);
}
_variables.Push(new Variable(variableDeclaration.Name, new Val(name, variableDeclaration.Type, ValKind.Pointer)));
}
private void EmitWhile(BoundWhile whileStatement)
{
var conditionLabel = LabelName();
var iterationLabel = LabelName();
var endLabel = LabelName();
_breakLabels.Push(endLabel);
_continueLabels.Push(conditionLabel);
_writer.Indented($"jmp {conditionLabel}");
_writer.WriteLine(iterationLabel);
EmitBlock(whileStatement.Body);
_writer.WriteLine(conditionLabel);
var result = EmitUnwrap(EmitExpression(whileStatement.Condition));
_writer.Indented($"jnz {result}, {iterationLabel}, {endLabel}");
_writer.WriteLine(endLabel);
_continueLabels.Pop();
_breakLabels.Pop();
}
}