using System.Diagnostics; using NubLang.TypeChecking.Node; namespace NubLang.Generation.QBE; public partial class QBEGenerator { private void EmitStatement(Statement statement) { switch (statement) { case Assignment assignment: EmitAssignment(assignment); break; case Break: EmitBreak(); break; case Continue: EmitContinue(); break; case If ifStatement: EmitIf(ifStatement); break; case Return @return: EmitReturn(@return); break; case StatementExpression statementExpression: EmitExpression(statementExpression.Expression); break; case VariableDeclaration variableDeclaration: EmitVariableDeclaration(variableDeclaration); break; case While whileStatement: EmitWhile(whileStatement); break; default: throw new ArgumentOutOfRangeException(nameof(statement)); } } private void EmitAssignment(Assignment assignment) { var destination = EmitExpression(assignment.Target); Debug.Assert(destination.Kind == ValKind.Pointer); EmitCopyIntoOrInitialize(assignment.Value, destination.Name); } private void EmitBreak() { _writer.Indented($"jmp {_breakLabels.Peek()}"); _codeIsReachable = false; } private void EmitContinue() { _writer.Indented($"jmp {_continueLabels.Peek()}"); _codeIsReachable = false; } private void EmitIf(If 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(Return @return) { if (@return.Value.HasValue) { var result = EmitUnwrap(EmitExpression(@return.Value.Value)); _writer.Indented($"ret {result}"); } else { _writer.Indented("ret"); } } private void EmitVariableDeclaration(VariableDeclaration 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); } Scope.Declare(variableDeclaration.Name, new Val(name, variableDeclaration.Type, ValKind.Pointer)); } private void EmitWhile(While 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(); } }