using System.Text; namespace Compiler; public sealed class Generator(List nodes) { public static string Emit(List nodes) { return new Generator(nodes).Emit(); } private IndentedTextWriter writer = new(); private string Emit() { writer.WriteLine(""" #include #include #include #include #include struct string { const char *data; int length; }; """); foreach (var node in nodes.OfType()) { var parameters = node.Parameters.Select(x => CType(x.Type, x.Name.Ident)); writer.WriteLine($"{CType(node.ReturnType, node.Name.Ident)}({string.Join(", ", parameters)});"); } writer.WriteLine(); foreach (var node in nodes.OfType()) { var parameters = node.Parameters.Select(x => CType(x.Type, x.Name.Ident)); writer.WriteLine($"{CType(node.ReturnType, node.Name.Ident)}({string.Join(", ", parameters)})"); writer.WriteLine("{"); using (writer.Indent()) { EmitStatement(node.Body); } writer.WriteLine("}"); writer.WriteLine(); } return writer.ToString(); } private void EmitStatement(NodeStatement node) { switch (node) { case NodeStatementBlock statement: EmitStatementBlock(statement); break; case NodeStatementFuncCall statement: EmitStatementFuncCall(statement); break; case NodeStatementReturn statement: EmitStatementReturn(statement); break; default: throw new ArgumentOutOfRangeException(nameof(node), node, null); } } private void EmitStatementBlock(NodeStatementBlock node) { writer.WriteLine("{"); using (writer.Indent()) { foreach (var statement in node.Statements) EmitStatement(statement); } writer.WriteLine("}"); } private void EmitStatementFuncCall(NodeStatementFuncCall node) { var name = EmitExpression(node.Func); var parameterValues = node.Parameters.Select(EmitExpression).ToList(); writer.WriteLine($"{name}({string.Join(", ", parameterValues)});"); } private void EmitStatementReturn(NodeStatementReturn statement) { var value = EmitExpression(statement.Value); writer.WriteLine($"return {value};"); } private string EmitExpression(NodeExpression node) { return node switch { NodeExpressionBoolLiteral expression => expression.Value.Value ? "true" : "false", NodeExpressionIntLiteral expression => expression.Value.Value.ToString(), NodeExpressionStringLiteral expression => $"(struct string){{ \"{expression.Value.Value}\", {expression.Value.Value.Length} }}", NodeExpressionIdent expression => expression.Value.Ident, _ => throw new ArgumentOutOfRangeException(nameof(node), node, null) }; } private static string CType(NodeType node, string? varName = null) { return node switch { NodeTypeVoid => "void" + (varName != null ? $" {varName}" : ""), NodeTypeBool => "bool" + (varName != null ? $" {varName}" : ""), NodeTypeCustom type => $"struct {type}" + (varName != null ? $" {varName}" : ""), NodeTypeSInt type => $"int{type.Width}_t" + (varName != null ? $" {varName}" : ""), NodeTypeUInt type => $"uint{type.Width}_t" + (varName != null ? $" {varName}" : ""), NodeTypePointer type => CType(type.To) + (varName != null ? $" *{varName}" : "*"), NodeTypeString => "struct string" + (varName != null ? $" {varName}" : ""), NodeTypeFunc type => $"{CType(type.ReturnType)} (*{varName})({string.Join(", ", type.Parameters.Select(p => CType(p)))})", _ => throw new ArgumentOutOfRangeException(nameof(node), node, null) }; } } internal class IndentedTextWriter { private readonly StringBuilder builder = new(); private int indentLevel; public IDisposable Indent() { indentLevel++; return new IndentScope(this); } public void WriteLine(string text) { WriteIndent(); builder.AppendLine(text); } public void Write(string text) { WriteIndent(); builder.Append(text); } public void WriteLine() { builder.AppendLine(); } public override string ToString() { return builder.ToString(); } private void WriteIndent() { if (builder.Length > 0) { var lastChar = builder[^1]; if (lastChar != '\n' && lastChar != '\r') return; } for (var i = 0; i < indentLevel; i++) { builder.Append(" "); } } private class IndentScope(IndentedTextWriter writer) : IDisposable { private bool disposed; public void Dispose() { if (disposed) return; writer.indentLevel--; disposed = true; } } }