diff --git a/src/lang/Nub.Lang/Diagnostics/Diagnostic.cs b/src/lang/Nub.Lang/Diagnostics/Diagnostic.cs index 6a859cc..8644ef4 100644 --- a/src/lang/Nub.Lang/Diagnostics/Diagnostic.cs +++ b/src/lang/Nub.Lang/Diagnostics/Diagnostic.cs @@ -82,7 +82,7 @@ public class Diagnostic if (Span.HasValue) { sb.AppendLine(); - AppendSourceContext(sb, Span.Value); + AppendSourceContext(sb, Span.Value, Severity); } if (!string.IsNullOrEmpty(Help)) @@ -105,7 +105,7 @@ public class Diagnostic }; } - private static void AppendSourceContext(StringBuilder sb, SourceSpan span) + private static void AppendSourceContext(StringBuilder sb, SourceSpan span, DiagnosticSeverity severity) { var lines = span.Text.Content.Split('\n'); var startLine = span.Start.Line; @@ -137,7 +137,7 @@ public class Diagnostic for (var lineNum = startLine; lineNum <= endLine; lineNum++) { AppendContextLine(sb, lineNum, lines[lineNum - 1], lineNumWidth, contextWidth); - AppendErrorIndicators(sb, span, lineNum, lines[lineNum - 1], lineNumWidth, contextWidth); + AppendErrorIndicators(sb, span, lineNum, lines[lineNum - 1], lineNumWidth, contextWidth, severity); } for (var lineNum = endLine + 1; lineNum <= contextEnd; lineNum++) @@ -159,13 +159,21 @@ public class Diagnostic sb.AppendLine(); } - private static void AppendErrorIndicators(StringBuilder sb, SourceSpan span, int lineNum, string line, int lineNumWidth, int contextWidth) + private static void AppendErrorIndicators(StringBuilder sb, SourceSpan span, int lineNum, string line, int lineNumWidth, int contextWidth, DiagnosticSeverity severity) { + var color = severity switch + { + DiagnosticSeverity.Info => ConsoleColors.Blue, + DiagnosticSeverity.Warning => ConsoleColors.Yellow, + DiagnosticSeverity.Error => ConsoleColors.Red, + _ => throw new ArgumentOutOfRangeException(nameof(severity), severity, null) + }; + sb.Append(ConsoleColors.Colorize('│' + " ", ConsoleColors.Faint)); sb.Append(new string(' ', lineNumWidth)); sb.Append(ConsoleColors.Colorize(" │ ", ConsoleColors.Faint)); var indicators = GetIndicatorsForLine(span, lineNum, line); - sb.Append(ConsoleColors.Colorize(indicators.PadRight(contextWidth), ConsoleColors.Red)); + sb.Append(ConsoleColors.Colorize(indicators.PadRight(contextWidth), color)); sb.Append(ConsoleColors.Colorize(" " + '│', ConsoleColors.Faint)); sb.AppendLine(); } diff --git a/src/lang/Nub.Lang/Frontend/Generation/QBEGenerator.cs b/src/lang/Nub.Lang/Frontend/Generation/QBEGenerator.cs index 6f2e022..b6531b7 100644 --- a/src/lang/Nub.Lang/Frontend/Generation/QBEGenerator.cs +++ b/src/lang/Nub.Lang/Frontend/Generation/QBEGenerator.cs @@ -165,6 +165,61 @@ public class QBEGenerator }}"; } + private int AlignmentOf(NubType type) + { + switch (type) + { + case NubPrimitiveType primitiveType: + { + switch (primitiveType.Kind) + { + case PrimitiveTypeKind.I64: + case PrimitiveTypeKind.U64: + case PrimitiveTypeKind.F64: + return 8; + case PrimitiveTypeKind.I32: + case PrimitiveTypeKind.U32: + case PrimitiveTypeKind.F32: + return 4; + case PrimitiveTypeKind.I16: + case PrimitiveTypeKind.U16: + return 2; + case PrimitiveTypeKind.I8: + case PrimitiveTypeKind.U8: + case PrimitiveTypeKind.Bool: + return 1; + default: + throw new ArgumentOutOfRangeException(); + } + } + case NubStructType nubStructType: + { + var definition = LookupStructDefinition(nubStructType.Namespace, nubStructType.Name); + // Struct alignment is the maximum alignment of its fields + return definition.Fields.Max(f => AlignmentOf(f.Type)); + } + case NubPointerType: + case NubArrayType: + { + return 8; // Pointer alignment (assuming 64-bit) + } + case NubFixedArrayType nubFixedArrayType: + { + // Array alignment is same as element alignment + return AlignmentOf(nubFixedArrayType.ElementType); + } + default: + { + throw new UnreachableException(); + } + } + } + + private int AlignTo(int offset, int alignment) + { + return (offset + alignment - 1) & ~(alignment - 1); + } + private int SizeOf(NubType type) { switch (type) @@ -197,7 +252,26 @@ public class QBEGenerator case NubStructType nubStructType: { var definition = LookupStructDefinition(nubStructType.Namespace, nubStructType.Name); - return definition.Fields.Sum(f => SizeOf(f.Type)); + + int size = 0; + int maxAlignment = 1; + + foreach (var field in definition.Fields) + { + int fieldAlignment = AlignmentOf(field.Type); + maxAlignment = Math.Max(maxAlignment, fieldAlignment); + + // Align current position for this field + size = AlignTo(size, fieldAlignment); + + // Add field size + size += SizeOf(field.Type); + } + + // Align final size to struct's alignment for array compatibility + size = AlignTo(size, maxAlignment); + + return size; } case NubPointerType: case NubArrayType: @@ -206,7 +280,8 @@ public class QBEGenerator } case NubFixedArrayType nubFixedArrayType: { - return SizeOf(nubFixedArrayType.ElementType) * nubFixedArrayType.Capacity; + int elementSize = SizeOf(nubFixedArrayType.ElementType); + return elementSize * nubFixedArrayType.Capacity + 8; // +8 for length/capacity info } default: { @@ -687,8 +762,9 @@ public class QBEGenerator private string GenerateArrayInitializer(ArrayInitializerNode arrayInitializer) { var capacity = GenerateExpression(arrayInitializer.Capacity); + var elementSize = SizeOf(arrayInitializer.ElementType); var capacityInBytes = GenVarName(); - _builder.AppendLine($" {capacityInBytes} =l mul {capacity}, {SizeOf(arrayInitializer.ElementType)}"); + _builder.AppendLine($" {capacityInBytes} =l mul {capacity}, {elementSize}"); var totalArraySize = GenVarName(); _builder.AppendLine($" {totalArraySize} =l add {capacityInBytes}, 8"); var outputName = GenVarName(); @@ -999,12 +1075,13 @@ public class QBEGenerator } } + private string GenerateStructInitializer(StructInitializerNode structInitializer) { var structDefinition = LookupStructDefinition(structInitializer.StructType.Namespace, structInitializer.StructType.Name); var structVar = GenVarName(); - var size = structDefinition.Fields.Sum(x => SizeOf(x.Type)); + var size = SizeOf(structInitializer.StructType); _builder.AppendLine($" {structVar} =l alloc8 {size}"); foreach (var field in structDefinition.Fields) @@ -1129,14 +1206,17 @@ public class QBEGenerator private string GenerateFixedArrayInitializer(FixedArrayInitializerNode fixedArrayInitializer) { - var capacityInBytes = SizeOf(fixedArrayInitializer.Type); + var totalSize = SizeOf(fixedArrayInitializer.Type); var outputName = GenVarName(); - _builder.AppendLine($" {outputName} =l alloc8 {capacityInBytes + 8}"); + _builder.AppendLine($" {outputName} =l alloc8 {totalSize}"); + _builder.AppendLine($" storel {fixedArrayInitializer.Capacity}, {outputName}"); var dataPtr = GenVarName(); _builder.AppendLine($" {dataPtr} =l add {outputName}, 8"); - _builder.AppendLine($" call $nub_memset(l {dataPtr}, w 0, l {capacityInBytes})"); + + var dataSize = totalSize - 8; + _builder.AppendLine($" call $nub_memset(l {dataPtr}, w 0, l {dataSize})"); return outputName; } @@ -1198,7 +1278,7 @@ public class QBEGenerator else { _builder.AppendLine($" call {funcName}({string.Join(", ", parameterStrings)})"); - return "this should never show up!"; + return "fuck"; } } @@ -1244,6 +1324,24 @@ public class QBEGenerator private int LookupMemberOffset(StructDefinitionNode structDefinition, string member) { - return structDefinition.Fields.TakeWhile(f => f.Name != member).Sum(f => SizeOf(f.Type)); + int offset = 0; + + foreach (var field in structDefinition.Fields) + { + if (field.Name == member) + { + return offset; + } + + int fieldAlignment = AlignmentOf(field.Type); + + // Align offset for this field + offset = AlignTo(offset, fieldAlignment); + + // Add field size + offset += SizeOf(field.Type); + } + + throw new ArgumentException($"Member '{member}' not found in struct"); } } \ No newline at end of file