....
This commit is contained in:
158
src/compiler/NubLang/Generation/QBE/QBEGenerator.Statement.cs
Normal file
158
src/compiler/NubLang/Generation/QBE/QBEGenerator.Statement.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user