diff --git a/example/main.nub b/example/main.nub index 5e946ff..08ed021 100644 --- a/example/main.nub +++ b/example/main.nub @@ -5,15 +5,19 @@ struct Human { } export func main(args: []^string): i64 { - let x = [3]f64 + let age: u64 = 23 - x[0] = 1 - x[1] = 2 - x[2] = 3 + let me = alloc Human { + age = &age + } - c::printf("%f\n", x[0]) - c::printf("%f\n", x[1]) - c::printf("%f\n", x[2]) + me.age^ = 24.5 + + test(me.age^) return 0 } + +func test(me: u64) { + c::printf("%d\n", me) +} \ No newline at end of file diff --git a/src/lang/Nub.Lang.CLI/Program.cs b/src/lang/Nub.Lang.CLI/Program.cs index 5f6e0c8..98d76fd 100644 --- a/src/lang/Nub.Lang.CLI/Program.cs +++ b/src/lang/Nub.Lang.CLI/Program.cs @@ -49,7 +49,7 @@ error = error || typeCheckResult.HasErrors; if (error) return 1; -var generator = new Generator(); +var generator = new QBEGenerator(); var result = generator.Generate(files); Console.Out.Write(result); diff --git a/src/lang/Nub.Lang/Frontend/Generation/Generator.cs b/src/lang/Nub.Lang/Frontend/Generation/QBEGenerator.cs similarity index 57% rename from src/lang/Nub.Lang/Frontend/Generation/Generator.cs rename to src/lang/Nub.Lang/Frontend/Generation/QBEGenerator.cs index ad70bf8..6f2e022 100644 --- a/src/lang/Nub.Lang/Frontend/Generation/Generator.cs +++ b/src/lang/Nub.Lang/Frontend/Generation/QBEGenerator.cs @@ -10,7 +10,7 @@ using Nub.Lang.Frontend.Typing; namespace Nub.Lang.Frontend.Generation; -public class Generator +public class QBEGenerator { private const string OutOfBoundsMessage = "Index is out of bounds\\n"; @@ -297,7 +297,7 @@ public class Generator foreach (var parameter in node.Parameters) { - var parameterName = parameter.Name; + var parameterName = "%" + parameter.Name; if (parameter.Type is NubPrimitiveType primitiveType) { @@ -319,24 +319,18 @@ public class Generator parameterName = GenVarName(); _builder.AppendLine($" {parameterName} =w extub %{parameter.Name}"); break; - default: - throw new ArgumentOutOfRangeException(); } } - + _variables[parameter.Name] = parameterName; } - _builder.AppendLine(); - GenerateBlock(node.Body); if (node.Body.Statements.LastOrDefault() is not ReturnNode) { if (node.ReturnType is NubVoidType) { - _builder.AppendLine(); - _builder.AppendLine(" # Implicit return"); _builder.AppendLine(" ret"); } } @@ -436,17 +430,10 @@ public class Generator var adjustedIndex = GenVarName(); _builder.AppendLine($" {adjustedIndex} =l mul {index}, {SizeOf(arrayType.ElementType)}"); - var offsetName = GenVarName(); - _builder.AppendLine($" {offsetName} =l add {startName}, {adjustedIndex}"); + var pointer = GenVarName(); + _builder.AppendLine($" {pointer} =l add {startName}, {adjustedIndex}"); - if (IsLargeType(arrayType.ElementType)) - { - _builder.AppendLine($" blit {value}, {offsetName}, {SizeOf(arrayType.ElementType)}"); - } - else - { - _builder.AppendLine($" {QBEStore(arrayType.ElementType)} {value}, {offsetName}"); - } + GenerateCopy(arrayType.ElementType, value, pointer); break; } case NubFixedArrayType fixedArrayType: @@ -457,17 +444,10 @@ public class Generator var adjustedIndex = GenVarName(); _builder.AppendLine($" {adjustedIndex} =l mul {index}, {SizeOf(fixedArrayType.ElementType)}"); - var offsetName = GenVarName(); - _builder.AppendLine($" {offsetName} =l add {startName}, {adjustedIndex}"); + var pointer = GenVarName(); + _builder.AppendLine($" {pointer} =l add {startName}, {adjustedIndex}"); - if (IsLargeType(fixedArrayType.ElementType)) - { - _builder.AppendLine($" blit {value}, {offsetName}, {SizeOf(fixedArrayType.ElementType)}"); - } - else - { - _builder.AppendLine($" {QBEStore(fixedArrayType.ElementType)} {value}, {offsetName}"); - } + GenerateCopy(fixedArrayType.ElementType, value, pointer); break; } default: @@ -501,17 +481,9 @@ public class Generator private void GenerateDereferenceAssignment(DereferenceAssignmentNode dereferenceAssignment) { - var location = GenerateExpression(dereferenceAssignment.Dereference.Expression); + var pointer = GenerateExpression(dereferenceAssignment.Dereference.Expression); var value = GenerateExpression(dereferenceAssignment.Value); - - if (IsLargeType(dereferenceAssignment.Value.Type)) - { - _builder.AppendLine($" blit {value}, {location}, {SizeOf(dereferenceAssignment.Value.Type)}"); - } - else - { - _builder.AppendLine($" {QBEStore(dereferenceAssignment.Value.Type)} {value}, {location}"); - } + GenerateCopy(dereferenceAssignment.Value.Type, value, pointer); } private void GenerateIf(IfNode ifStatement) @@ -547,20 +519,13 @@ public class Generator var offset = LookupMemberOffset(structDefinition, memberAssignment.MemberAccess.Member); var item = GenerateExpression(memberAssignment.MemberAccess.Expression); - var offsetName = GenVarName(); + var pointer = GenVarName(); - _builder.AppendLine($" {offsetName} =l add {item}, {offset}"); + _builder.AppendLine($" {pointer} =l add {item}, {offset}"); var value = GenerateExpression(memberAssignment.Value); - if (IsLargeType(memberAssignment.Value.Type)) - { - _builder.AppendLine($" blit {value}, {offsetName}, {SizeOf(memberAssignment.Value.Type)}"); - } - else - { - _builder.AppendLine($" {QBEStore(memberAssignment.Value.Type)} {value}, {offsetName}"); - } + GenerateCopy(memberAssignment.Value.Type, value, pointer); } private void GenerateReturn(ReturnNode @return) @@ -575,48 +540,32 @@ public class Generator _builder.AppendLine(" ret"); } } - + private void GenerateVariableAssignment(VariableAssignmentNode variableAssignment) { - var result = GenerateExpression(variableAssignment.Value); - _builder.AppendLine($" storel {result}, {_variables[variableAssignment.Identifier.Identifier]}"); + var value = GenerateExpression(variableAssignment.Value); + var pointer = _variables[variableAssignment.Identifier.Identifier]; + GenerateCopy(variableAssignment.Value.Type, value, pointer); } private void GenerateVariableDeclaration(VariableDeclarationNode variableDeclaration) { - var type = variableDeclaration.ExplicitType.Value ?? variableDeclaration.Value.Value?.Type!; - - string pointerName; + var type = variableDeclaration.ExplicitType.Value ?? variableDeclaration.Value.Value!.Type; + var pointer = GenVarName(); + _builder.AppendLine($" {pointer} =l alloc8 {SizeOf(type)}"); if (variableDeclaration.Value.HasValue) { - var result = GenerateExpression(variableDeclaration.Value.Value); - if (IsLargeType(type)) - { - pointerName = result; - } - else - { - pointerName = GenVarName(); - _builder.AppendLine($" {pointerName} =l alloc8 {SizeOf(type)}"); - _builder.AppendLine($" {QBEStore(type)} {result}, {pointerName}"); - } + var value = GenerateExpression(variableDeclaration.Value.Value); + GenerateCopy(variableDeclaration.Value.Value.Type, value, pointer); } else { - pointerName = GenVarName(); - _builder.AppendLine($" {pointerName} =l alloc8 {SizeOf(type)}"); - if (IsLargeType(type)) - { - _builder.AppendLine($" call $nub_memset(l {pointerName}, ub 0, l {SizeOf(type)})"); - } - else - { - _builder.AppendLine($" {QBEStore(type)} 0, {pointerName}"); - } + var pointerName = GenVarName(); + _variables[variableDeclaration.Name] = pointerName; } - - _variables[variableDeclaration.Name] = pointerName; + + _variables[variableDeclaration.Name] = pointer; } private void GenerateWhile(WhileNode whileStatement) @@ -645,10 +594,9 @@ public class Generator return expression switch { AddressOfNode addressOf => GenerateAddressOf(addressOf), - ArrayIndexAccessNode arrayIndex => GenerateArrayIndex(arrayIndex), + ArrayIndexAccessNode arrayIndex => GenerateArrayAccessIndex(arrayIndex), ArrayInitializerNode arrayInitializer => GenerateArrayInitializer(arrayInitializer), BinaryExpressionNode binaryExpression => GenerateBinaryExpression(binaryExpression), - // CastNode cast => GenerateCast(cast), DereferenceNode dereference => GenerateDereference(dereference), FixedArrayInitializerNode fixedArrayInitializer => GenerateFixedArrayInitializer(fixedArrayInitializer), FuncCallNode funcCallExpression => GenerateFuncCall(funcCallExpression), @@ -661,12 +609,12 @@ public class Generator }; } - private string GenerateArrayIndex(ArrayIndexAccessNode arrayIndexAccess) + private string GenerateArrayIndexPointer(ArrayIndexAccessNode arrayIndexAccess) { var array = GenerateExpression(arrayIndexAccess.Array); var index = GenerateExpression(arrayIndexAccess.Index); GenerateArrayBoundsCheck(array, index); - + switch (arrayIndexAccess.Array.Type) { case NubArrayType arrayType: @@ -677,17 +625,7 @@ public class Generator _builder.AppendLine($" {offsetPointerName} =l mul {index}, {SizeOf(arrayType.ElementType)}"); var resultPointerName = GenVarName(); _builder.AppendLine($" {resultPointerName} =l add {firstItemPointerName}, {offsetPointerName}"); - - if (IsLargeType(arrayType.ElementType)) - { - return resultPointerName; - } - else - { - var outputName = GenVarName(); - _builder.AppendLine($" {outputName} {QBEAssign(arrayType.ElementType)} {QBELoad(arrayType.ElementType)} {resultPointerName}"); - return outputName; - } + return resultPointerName; } case NubFixedArrayType fixedArrayType: { @@ -697,17 +635,7 @@ public class Generator _builder.AppendLine($" {offsetPointerName} =l mul {index}, {SizeOf(fixedArrayType.ElementType)}"); var resultPointerName = GenVarName(); _builder.AppendLine($" {resultPointerName} =l add {firstItemPointerName}, {offsetPointerName}"); - - if (IsLargeType(fixedArrayType.ElementType)) - { - return resultPointerName; - } - else - { - var outputName = GenVarName(); - _builder.AppendLine($" {outputName} {QBEAssign(fixedArrayType.ElementType)} {QBELoad(fixedArrayType.ElementType)} {resultPointerName}"); - return outputName; - } + return resultPointerName; } default: { @@ -715,6 +643,22 @@ public class Generator } } } + + private string GenerateArrayAccessIndex(ArrayIndexAccessNode arrayIndexAccess) + { + var pointerName = GenerateArrayIndexPointer(arrayIndexAccess); + + if (IsLargeType(arrayIndexAccess.Type)) + { + return pointerName; + } + else + { + var outputName = GenVarName(); + _builder.AppendLine($" {outputName} {QBEAssign(arrayIndexAccess.Type)} {QBELoad(arrayIndexAccess.Type)} {pointerName}"); + return outputName; + } + } private void GenerateArrayBoundsCheck(string array, string index) { @@ -768,30 +712,18 @@ public class Generator private string GenerateAddressOf(AddressOfNode addressOf) { - var result = GenerateExpression(addressOf.Expression); - var outputName = GenVarName(); - switch (addressOf.Expression.Type) + switch (addressOf.Expression) { - case NubPointerType: - case NubStructType: - case NubPrimitiveType { Kind: PrimitiveTypeKind.I64 }: - case NubPrimitiveType { Kind: PrimitiveTypeKind.F64 }: - case NubPrimitiveType { Kind: PrimitiveTypeKind.U64 }: - _builder.AppendLine($" {outputName} =l alloc8 8"); - _builder.AppendLine($" storel {result}, {outputName}"); - return outputName; - case NubPrimitiveType { Kind: PrimitiveTypeKind.I32 }: - case NubPrimitiveType { Kind: PrimitiveTypeKind.U32 }: - case NubPrimitiveType { Kind: PrimitiveTypeKind.I16 }: - case NubPrimitiveType { Kind: PrimitiveTypeKind.U16 }: - case NubPrimitiveType { Kind: PrimitiveTypeKind.I8 }: - case NubPrimitiveType { Kind: PrimitiveTypeKind.U8 }: - case NubPrimitiveType { Kind: PrimitiveTypeKind.F32 }: - _builder.AppendLine($" {outputName} =l alloc8 4"); - _builder.AppendLine($" storew {result}, {outputName}"); - return outputName; + case ArrayIndexAccessNode arrayIndexAccess: + return GenerateArrayIndexPointer(arrayIndexAccess); + case DereferenceNode dereference: + return GenerateExpression(dereference.Expression); + case IdentifierNode identifier: + return _variables[identifier.Identifier]; + case MemberAccessNode memberAccess: + return GenerateMemberAccessPointer(memberAccess); default: - throw new ArgumentOutOfRangeException(); + throw new UnreachableException(); } } @@ -1021,462 +953,9 @@ public class Generator throw new NotSupportedException($"Binary operator {binaryExpression.Operator} for types {binaryExpression.Left.Type} and {binaryExpression.Right.Type} not supported"); } - // private string GenerateCast(CastNode cast) - // { - // var input = GenerateExpression(cast.Expression); - // var outputType = cast.TargetType; - // var inputType = cast.Expression.Type; - // - // if (inputType.Equals(outputType)) - // { - // return input; - // } - // - // if (outputType is not NubPrimitiveType primitiveOutputType || inputType is not NubPrimitiveType primitiveInputType) - // { - // throw new NotSupportedException("Casting is only supported for primitive types"); - // } - // - // var outputName = GenVarName(); - // - // switch (primitiveInputType.Kind) - // { - // case PrimitiveTypeKind.I64: - // switch (primitiveOutputType.Kind) - // { - // case PrimitiveTypeKind.I64: - // case PrimitiveTypeKind.U64: - // case PrimitiveTypeKind.I32: - // case PrimitiveTypeKind.U32: - // case PrimitiveTypeKind.I16: - // case PrimitiveTypeKind.U16: - // case PrimitiveTypeKind.I8: - // case PrimitiveTypeKind.Any: - // case PrimitiveTypeKind.U8: - // return input; - // case PrimitiveTypeKind.F64: - // _builder.AppendLine($" {outputName} =d sltof {input}"); - // return outputName; - // case PrimitiveTypeKind.F32: - // _builder.AppendLine($" {outputName} =s sltof {input}"); - // return outputName; - // case PrimitiveTypeKind.String: - // _builder.AppendLine($" {outputName} =l call $nub_i64_to_string(l {input})"); - // return outputName; - // case PrimitiveTypeKind.Bool: - // default: - // throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); - // } - // case PrimitiveTypeKind.I32: - // switch (primitiveOutputType.Kind) - // { - // case PrimitiveTypeKind.I64: - // case PrimitiveTypeKind.U64: - // _builder.AppendLine($" {outputName} =l extsw {input}"); - // return outputName; - // case PrimitiveTypeKind.I32: - // case PrimitiveTypeKind.U32: - // case PrimitiveTypeKind.I16: - // case PrimitiveTypeKind.U16: - // case PrimitiveTypeKind.I8: - // case PrimitiveTypeKind.U8: - // return input; - // case PrimitiveTypeKind.F64: - // var extName = GenVarName(); - // _builder.AppendLine($" {extName} =l extsw {input}"); - // _builder.AppendLine($" {outputName} =d sltof {extName}"); - // return outputName; - // case PrimitiveTypeKind.F32: - // _builder.AppendLine($" {outputName} =s swtof {input}"); - // return outputName; - // case PrimitiveTypeKind.String: - // _builder.AppendLine($" {outputName} =l call $nub_i32_to_string(w {input})"); - // return outputName; - // case PrimitiveTypeKind.Any: - // var extAnyName = GenVarName(); - // _builder.AppendLine($" {extAnyName} =l extsw {input}"); - // return extAnyName; - // case PrimitiveTypeKind.Bool: - // default: - // throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); - // } - // case PrimitiveTypeKind.I16: - // switch (primitiveOutputType.Kind) - // { - // case PrimitiveTypeKind.I64: - // case PrimitiveTypeKind.U64: - // _builder.AppendLine($" {outputName} =l extsh {input}"); - // return outputName; - // case PrimitiveTypeKind.I32: - // case PrimitiveTypeKind.U32: - // _builder.AppendLine($" {outputName} =w extsh {input}"); - // return outputName; - // case PrimitiveTypeKind.I16: - // case PrimitiveTypeKind.U16: - // case PrimitiveTypeKind.I8: - // case PrimitiveTypeKind.U8: - // return input; - // case PrimitiveTypeKind.F64: - // { - // var extName = GenVarName(); - // _builder.AppendLine($" {extName} =l extsh {input}"); - // _builder.AppendLine($" {outputName} =d sltof {extName}"); - // return outputName; - // } - // case PrimitiveTypeKind.F32: - // { - // var extName = GenVarName(); - // _builder.AppendLine($" {extName} =w extsh {input}"); - // _builder.AppendLine($" {outputName} =s swtof {extName}"); - // return outputName; - // } - // case PrimitiveTypeKind.String: - // { - // var extName = GenVarName(); - // _builder.AppendLine($" {extName} =w extsh {input}"); - // _builder.AppendLine($" {outputName} =l call $nub_i32_to_string(w {extName})"); - // return outputName; - // } - // case PrimitiveTypeKind.Any: - // { - // var extName = GenVarName(); - // _builder.AppendLine($" {extName} =l extsh {input}"); - // return extName; - // } - // case PrimitiveTypeKind.Bool: - // default: - // throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); - // } - // case PrimitiveTypeKind.I8: - // switch (primitiveOutputType.Kind) - // { - // case PrimitiveTypeKind.I64: - // case PrimitiveTypeKind.U64: - // _builder.AppendLine($" {outputName} =l extsb {input}"); - // return outputName; - // case PrimitiveTypeKind.I32: - // case PrimitiveTypeKind.U32: - // case PrimitiveTypeKind.I16: - // case PrimitiveTypeKind.U16: - // _builder.AppendLine($" {outputName} =w extsb {input}"); - // return outputName; - // case PrimitiveTypeKind.I8: - // case PrimitiveTypeKind.U8: - // return input; - // case PrimitiveTypeKind.F64: - // { - // var extName = GenVarName(); - // _builder.AppendLine($" {extName} =l extsb {input}"); - // _builder.AppendLine($" {outputName} =d sltof {extName}"); - // return outputName; - // } - // case PrimitiveTypeKind.F32: - // { - // var extName = GenVarName(); - // _builder.AppendLine($" {extName} =w extsb {input}"); - // _builder.AppendLine($" {outputName} =s swtof {extName}"); - // return outputName; - // } - // case PrimitiveTypeKind.String: - // { - // var extName = GenVarName(); - // _builder.AppendLine($" {extName} =w extsb {input}"); - // _builder.AppendLine($" {outputName} =l call $nub_i32_to_string(w {extName})"); - // return outputName; - // } - // case PrimitiveTypeKind.Any: - // { - // var extName = GenVarName(); - // _builder.AppendLine($" {extName} =l extsb {input}"); - // return extName; - // } - // case PrimitiveTypeKind.Bool: - // default: - // throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); - // } - // case PrimitiveTypeKind.U64: - // switch (primitiveOutputType.Kind) - // { - // case PrimitiveTypeKind.I64: - // case PrimitiveTypeKind.U64: - // case PrimitiveTypeKind.I32: - // case PrimitiveTypeKind.U32: - // case PrimitiveTypeKind.I16: - // case PrimitiveTypeKind.U16: - // case PrimitiveTypeKind.I8: - // case PrimitiveTypeKind.U8: - // return input; - // case PrimitiveTypeKind.F64: - // _builder.AppendLine($" {outputName} =d ultof {input}"); - // return outputName; - // case PrimitiveTypeKind.F32: - // _builder.AppendLine($" {outputName} =s ultof {input}"); - // return outputName; - // case PrimitiveTypeKind.String: - // _builder.AppendLine($" {outputName} =l call $nub_u64_to_string(l {input})"); - // return outputName; - // case PrimitiveTypeKind.Any: - // return input; - // case PrimitiveTypeKind.Bool: - // default: - // throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); - // } - // case PrimitiveTypeKind.U32: - // switch (primitiveOutputType.Kind) - // { - // case PrimitiveTypeKind.I64: - // case PrimitiveTypeKind.U64: - // _builder.AppendLine($" {outputName} =l extuw {input}"); - // return outputName; - // case PrimitiveTypeKind.I32: - // case PrimitiveTypeKind.U32: - // case PrimitiveTypeKind.I16: - // case PrimitiveTypeKind.U16: - // case PrimitiveTypeKind.I8: - // case PrimitiveTypeKind.U8: - // return input; - // case PrimitiveTypeKind.F64: - // var extName = GenVarName(); - // _builder.AppendLine($" {extName} =l extuw {input}"); - // _builder.AppendLine($" {outputName} =d ultof {extName}"); - // return outputName; - // case PrimitiveTypeKind.F32: - // _builder.AppendLine($" {outputName} =s uwtof {input}"); - // return outputName; - // case PrimitiveTypeKind.String: - // _builder.AppendLine($" {outputName} =l call $nub_u32_to_string(w {input})"); - // return outputName; - // case PrimitiveTypeKind.Any: - // var extAnyName = GenVarName(); - // _builder.AppendLine($" {extAnyName} =l extuw {input}"); - // return extAnyName; - // case PrimitiveTypeKind.Bool: - // default: - // throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); - // } - // case PrimitiveTypeKind.U16: - // switch (primitiveOutputType.Kind) - // { - // case PrimitiveTypeKind.I64: - // case PrimitiveTypeKind.U64: - // _builder.AppendLine($" {outputName} =l extuh {input}"); - // return outputName; - // case PrimitiveTypeKind.I32: - // case PrimitiveTypeKind.U32: - // _builder.AppendLine($" {outputName} =w extuh {input}"); - // return outputName; - // case PrimitiveTypeKind.I16: - // case PrimitiveTypeKind.U16: - // case PrimitiveTypeKind.I8: - // case PrimitiveTypeKind.U8: - // return input; - // case PrimitiveTypeKind.F64: - // { - // var extName = GenVarName(); - // _builder.AppendLine($" {extName} =l extuh {input}"); - // _builder.AppendLine($" {outputName} =d ultof {extName}"); - // return outputName; - // } - // case PrimitiveTypeKind.F32: - // { - // var extName = GenVarName(); - // _builder.AppendLine($" {extName} =w extuh {input}"); - // _builder.AppendLine($" {outputName} =s uwtof {extName}"); - // return outputName; - // } - // case PrimitiveTypeKind.String: - // { - // var extName = GenVarName(); - // _builder.AppendLine($" {extName} =w extuh {input}"); - // _builder.AppendLine($" {outputName} =l call $nub_u32_to_string(w {extName})"); - // return outputName; - // } - // case PrimitiveTypeKind.Any: - // { - // var extName = GenVarName(); - // _builder.AppendLine($" {extName} =l extuh {input}"); - // return extName; - // } - // case PrimitiveTypeKind.Bool: - // default: - // throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); - // } - // case PrimitiveTypeKind.U8: - // switch (primitiveOutputType.Kind) - // { - // case PrimitiveTypeKind.I64: - // case PrimitiveTypeKind.U64: - // _builder.AppendLine($" {outputName} =l extub {input}"); - // return outputName; - // case PrimitiveTypeKind.I32: - // case PrimitiveTypeKind.U32: - // case PrimitiveTypeKind.I16: - // case PrimitiveTypeKind.U16: - // _builder.AppendLine($" {outputName} =w extub {input}"); - // return outputName; - // case PrimitiveTypeKind.I8: - // case PrimitiveTypeKind.U8: - // return input; - // case PrimitiveTypeKind.F64: - // { - // var extName = GenVarName(); - // _builder.AppendLine($" {extName} =l extub {input}"); - // _builder.AppendLine($" {outputName} =d ultof {extName}"); - // return outputName; - // } - // case PrimitiveTypeKind.F32: - // { - // var extName = GenVarName(); - // _builder.AppendLine($" {extName} =w extub {input}"); - // _builder.AppendLine($" {outputName} =s uwtof {extName}"); - // return outputName; - // } - // case PrimitiveTypeKind.String: - // { - // var extName = GenVarName(); - // _builder.AppendLine($" {extName} =w extub {input}"); - // _builder.AppendLine($" {outputName} =l call $nub_u32_to_string(w {extName})"); - // return outputName; - // } - // case PrimitiveTypeKind.Any: - // { - // var extName = GenVarName(); - // _builder.AppendLine($" {extName} =l extub {input}"); - // return extName; - // } - // case PrimitiveTypeKind.Bool: - // default: - // throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); - // } - // case PrimitiveTypeKind.F64: - // switch (primitiveOutputType.Kind) - // { - // case PrimitiveTypeKind.F64: - // case PrimitiveTypeKind.Any: - // return input; - // case PrimitiveTypeKind.F32: - // _builder.AppendLine($" {outputName} =s dtos {input}"); - // return outputName; - // case PrimitiveTypeKind.I64: - // _builder.AppendLine($" {outputName} =l dtosi {input}"); - // return outputName; - // case PrimitiveTypeKind.I32: - // case PrimitiveTypeKind.I16: - // case PrimitiveTypeKind.I8: - // _builder.AppendLine($" {outputName} =w dtosi {input}"); - // return outputName; - // case PrimitiveTypeKind.U64: - // _builder.AppendLine($" {outputName} =l dtoui {input}"); - // return outputName; - // case PrimitiveTypeKind.U32: - // case PrimitiveTypeKind.U16: - // case PrimitiveTypeKind.U8: - // _builder.AppendLine($" {outputName} =w dtoui {input}"); - // return outputName; - // case PrimitiveTypeKind.String: - // _builder.AppendLine($" {outputName} =l call $nub_f64_to_string(d {input})"); - // return outputName; - // case PrimitiveTypeKind.Bool: - // default: - // throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); - // } - // case PrimitiveTypeKind.F32: - // switch (primitiveOutputType.Kind) - // { - // case PrimitiveTypeKind.F64: - // _builder.AppendLine($" {outputName} =d stod {input}"); - // return outputName; - // case PrimitiveTypeKind.F32: - // return input; - // case PrimitiveTypeKind.I64: - // _builder.AppendLine($" {outputName} =l stosi {input}"); - // return outputName; - // case PrimitiveTypeKind.I32: - // case PrimitiveTypeKind.I16: - // case PrimitiveTypeKind.I8: - // _builder.AppendLine($" {outputName} =w stosi {input}"); - // return outputName; - // case PrimitiveTypeKind.U64: - // _builder.AppendLine($" {outputName} =l stoui {input}"); - // return outputName; - // case PrimitiveTypeKind.U32: - // case PrimitiveTypeKind.U16: - // case PrimitiveTypeKind.U8: - // _builder.AppendLine($" {outputName} =w stoui {input}"); - // return outputName; - // case PrimitiveTypeKind.String: - // _builder.AppendLine($" {outputName} =l call $nub_f32_to_string(s {input})"); - // return outputName; - // case PrimitiveTypeKind.Any: - // throw new NotImplementedException(); - // case PrimitiveTypeKind.Bool: - // default: - // throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); - // } - // case PrimitiveTypeKind.Bool: - // switch (primitiveOutputType.Kind) - // { - // case PrimitiveTypeKind.Bool: - // return input; - // case PrimitiveTypeKind.Any: - // _builder.AppendLine($" {outputName} =l extsw {input}"); - // return outputName; - // case PrimitiveTypeKind.String: - // _builder.AppendLine($" {outputName} =l call $nub_bool_to_string(s {input})"); - // return outputName; - // case PrimitiveTypeKind.I64: - // case PrimitiveTypeKind.I32: - // case PrimitiveTypeKind.I16: - // case PrimitiveTypeKind.I8: - // case PrimitiveTypeKind.U64: - // case PrimitiveTypeKind.U32: - // case PrimitiveTypeKind.U16: - // case PrimitiveTypeKind.U8: - // case PrimitiveTypeKind.F64: - // case PrimitiveTypeKind.F32: - // default: - // throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); - // } - // case PrimitiveTypeKind.String: - // switch (primitiveOutputType.Kind) - // { - // case PrimitiveTypeKind.String: - // case PrimitiveTypeKind.Any: - // return input; - // case PrimitiveTypeKind.I64: - // case PrimitiveTypeKind.I32: - // case PrimitiveTypeKind.I16: - // case PrimitiveTypeKind.I8: - // case PrimitiveTypeKind.U64: - // case PrimitiveTypeKind.U32: - // case PrimitiveTypeKind.U16: - // case PrimitiveTypeKind.U8: - // case PrimitiveTypeKind.F64: - // case PrimitiveTypeKind.F32: - // case PrimitiveTypeKind.Bool: - // default: - // throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); - // } - // case PrimitiveTypeKind.Any: - // return input; - // default: - // throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); - // } - // } - private string GenerateIdentifier(IdentifierNode identifier) { - var variable = _variables[identifier.Identifier]; - if (IsLargeType(identifier.Type)) - { - return variable; - } - else - { - var outputName = GenVarName(); - _builder.AppendLine($" {outputName} {QBEAssign(identifier.Type)} {QBELoad(identifier.Type)} {variable}"); - return outputName; - } + return _variables[identifier.Identifier]; } private string GenerateLiteral(LiteralNode literal) @@ -1534,33 +1013,17 @@ public class Generator if (structInitializer.Initializers.TryGetValue(field.Name, out var fieldValue)) { - var var = GenerateExpression(fieldValue); - var offsetName = GenVarName(); - _builder.AppendLine($" {offsetName} =l add {structVar}, {offset}"); - - if (IsLargeType(field.Type)) - { - _builder.AppendLine($" blit {var}, {offsetName}, {SizeOf(field.Type)}"); - } - else - { - _builder.AppendLine($" {QBEStore(field.Type)} {var}, {offsetName}"); - } + var value = GenerateExpression(fieldValue); + var pointer = GenVarName(); + _builder.AppendLine($" {pointer} =l add {structVar}, {offset}"); + GenerateCopy(field.Type, value, pointer); } else if (field.Value.HasValue) { - var var = GenerateExpression(field.Value.Value); - var offsetName = GenVarName(); - _builder.AppendLine($" {offsetName} =l add {structVar}, {offset}"); - - if (IsLargeType(field.Type)) - { - _builder.AppendLine($" blit {var}, {offsetName}, {SizeOf(field.Type)}"); - } - else - { - _builder.AppendLine($" {QBEStore(field.Type)} {var}, {offsetName}"); - } + var value = GenerateExpression(field.Value.Value); + var pointer = GenVarName(); + _builder.AppendLine($" {pointer} =l add {structVar}, {offset}"); + GenerateCopy(field.Type, value, pointer); } else { @@ -1618,22 +1081,19 @@ public class Generator throw new NotSupportedException($"Unary operator {unaryExpression.Operator} for type {unaryExpression.Operand.Type} not supported"); } - private string GenerateMemberAccess(MemberAccessNode memberAccess) + private string GenerateMemberAccessPointer(MemberAccessNode memberAccess) { var item = GenerateExpression(memberAccess.Expression); - switch (memberAccess.Expression.Type) { case NubArrayType: { if (memberAccess.Member == "count") { - var outputName = GenVarName(); - _builder.AppendLine($" {outputName} =l loadl {item}"); - return outputName; + return item; } - throw new ArgumentOutOfRangeException(nameof(memberAccess.Member)); + throw new UnreachableException(nameof(memberAccess.Member)); } case NubStructType structType: { @@ -1642,26 +1102,31 @@ public class Generator var offsetName = GenVarName(); _builder.AppendLine($" {offsetName} =l add {item}, {offset}"); - - if (IsLargeType(memberAccess.Type)) - { - return offsetName; - } - else - { - var outputName = GenVarName(); - _builder.AppendLine($" {outputName} {QBEAssign(memberAccess.Type)} {QBELoad(memberAccess.Type)} {offsetName}"); - - return outputName; - } + return offsetName; } default: { - throw new ArgumentOutOfRangeException(nameof(memberAccess.Expression.Type)); + throw new UnreachableException(nameof(memberAccess.Expression.Type)); } } } + private string GenerateMemberAccess(MemberAccessNode memberAccess) + { + var pointer = GenerateMemberAccessPointer(memberAccess); + + if (IsLargeType(memberAccess.Type)) + { + return pointer; + } + else + { + var outputName = GenVarName(); + _builder.AppendLine($" {outputName} {QBEAssign(memberAccess.Type)} {QBELoad(memberAccess.Type)} {pointer}"); + return outputName; + } + } + private string GenerateFixedArrayInitializer(FixedArrayInitializerNode fixedArrayInitializer) { var capacityInBytes = SizeOf(fixedArrayInitializer.Type); @@ -1737,6 +1202,18 @@ public class Generator } } + private void GenerateCopy(NubType type, string value, string destinationPointer) + { + if (IsLargeType(type)) + { + _builder.AppendLine($" blit {value}, {destinationPointer}, {SizeOf(type)}"); + } + else + { + _builder.AppendLine($" {QBEStore(type)} {value}, {destinationPointer}"); + } + } + private string GenVarName() { return $"%v{++_variableIndex}"; diff --git a/src/lang/Nub.Lang/Frontend/Parsing/Expressions/AddressOfNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/AddressOfNode.cs index f3edb6f..9209ffe 100644 --- a/src/lang/Nub.Lang/Frontend/Parsing/Expressions/AddressOfNode.cs +++ b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/AddressOfNode.cs @@ -2,7 +2,7 @@ using Nub.Lang.Frontend.Lexing; namespace Nub.Lang.Frontend.Parsing.Expressions; -public class AddressOfNode(IReadOnlyList tokens, ExpressionNode expression) : ExpressionNode(tokens) +public class AddressOfNode(IReadOnlyList tokens, LValueNode expression) : ExpressionNode(tokens) { - public ExpressionNode Expression { get; } = expression; + public LValueNode Expression { get; } = expression; } \ No newline at end of file diff --git a/src/lang/Nub.Lang/Frontend/Parsing/Expressions/ArrayIndexAccessNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/ArrayIndexAccessNode.cs index cda2740..c0a1338 100644 --- a/src/lang/Nub.Lang/Frontend/Parsing/Expressions/ArrayIndexAccessNode.cs +++ b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/ArrayIndexAccessNode.cs @@ -2,7 +2,7 @@ using Nub.Lang.Frontend.Lexing; namespace Nub.Lang.Frontend.Parsing.Expressions; -public class ArrayIndexAccessNode(IReadOnlyList tokens, ExpressionNode array, ExpressionNode index) : ExpressionNode(tokens) +public class ArrayIndexAccessNode(IReadOnlyList tokens, ExpressionNode array, ExpressionNode index) : LValueNode(tokens) { public ExpressionNode Array { get; } = array; public ExpressionNode Index { get; } = index; diff --git a/src/lang/Nub.Lang/Frontend/Parsing/Expressions/CastNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/CastNode.cs deleted file mode 100644 index 5fc33b8..0000000 --- a/src/lang/Nub.Lang/Frontend/Parsing/Expressions/CastNode.cs +++ /dev/null @@ -1,10 +0,0 @@ -// using Nub.Lang.Frontend.Lexing; -// using Nub.Lang.Frontend.Typing; -// -// namespace Nub.Lang.Frontend.Parsing.Expressions; -// -// public class CastNode(IReadOnlyList tokens, NubType targetType, ExpressionNode expression) : ExpressionNode(tokens) -// { -// public NubType TargetType { get; } = targetType; -// public ExpressionNode Expression { get; } = expression; -// } \ No newline at end of file diff --git a/src/lang/Nub.Lang/Frontend/Parsing/Expressions/DereferenceNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/DereferenceNode.cs index 4f7889a..e91584e 100644 --- a/src/lang/Nub.Lang/Frontend/Parsing/Expressions/DereferenceNode.cs +++ b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/DereferenceNode.cs @@ -2,7 +2,7 @@ using Nub.Lang.Frontend.Lexing; namespace Nub.Lang.Frontend.Parsing.Expressions; -public class DereferenceNode(IReadOnlyList tokens, ExpressionNode expression) : ExpressionNode(tokens) +public class DereferenceNode(IReadOnlyList tokens, ExpressionNode expression) : LValueNode(tokens) { public ExpressionNode Expression { get; } = expression; } \ No newline at end of file diff --git a/src/lang/Nub.Lang/Frontend/Parsing/Expressions/ExpressionNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/ExpressionNode.cs index 06afde0..9a749c3 100644 --- a/src/lang/Nub.Lang/Frontend/Parsing/Expressions/ExpressionNode.cs +++ b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/ExpressionNode.cs @@ -11,4 +11,6 @@ public abstract class ExpressionNode(IReadOnlyList tokens) : Node(tokens) get => _type ?? throw new Exception("Tried to access expression type before type was populated"); set => _type = value; } -} \ No newline at end of file +} + +public abstract class LValueNode(IReadOnlyList tokens) : ExpressionNode(tokens); diff --git a/src/lang/Nub.Lang/Frontend/Parsing/Expressions/IdentifierNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/IdentifierNode.cs index d9f67a9..877354e 100644 --- a/src/lang/Nub.Lang/Frontend/Parsing/Expressions/IdentifierNode.cs +++ b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/IdentifierNode.cs @@ -2,7 +2,7 @@ namespace Nub.Lang.Frontend.Parsing.Expressions; -public class IdentifierNode(IReadOnlyList tokens, string identifier) : ExpressionNode(tokens) +public class IdentifierNode(IReadOnlyList tokens, string identifier) : LValueNode(tokens) { public string Identifier { get; } = identifier; diff --git a/src/lang/Nub.Lang/Frontend/Parsing/Expressions/MemberAccessNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/MemberAccessNode.cs index a5e913a..c2aff51 100644 --- a/src/lang/Nub.Lang/Frontend/Parsing/Expressions/MemberAccessNode.cs +++ b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/MemberAccessNode.cs @@ -2,7 +2,7 @@ namespace Nub.Lang.Frontend.Parsing.Expressions; -public class MemberAccessNode(IReadOnlyList tokens, ExpressionNode expression, string member) : ExpressionNode(tokens) +public class MemberAccessNode(IReadOnlyList tokens, ExpressionNode expression, string member) : LValueNode(tokens) { public ExpressionNode Expression { get; } = expression; public string Member { get; } = member; diff --git a/src/lang/Nub.Lang/Frontend/Parsing/Parser.cs b/src/lang/Nub.Lang/Frontend/Parsing/Parser.cs index c408c54..20c3a09 100644 --- a/src/lang/Nub.Lang/Frontend/Parsing/Parser.cs +++ b/src/lang/Nub.Lang/Frontend/Parsing/Parser.cs @@ -495,20 +495,18 @@ public class Parser expr = expression; break; } - // case Symbol.LessThan: - // { - // var type = ParseType(); - // ExpectSymbol(Symbol.GreaterThan); - // ExpectSymbol(Symbol.OpenParen); - // var expressionToCast = ParseExpression(); - // ExpectSymbol(Symbol.CloseParen); - // expr = new CastNode(GetTokensForNode(startIndex), type, expressionToCast); - // break; - // } case Symbol.Ampersand: { var expression = ParsePrimaryExpression(); - expr = new AddressOfNode(GetTokensForNode(startIndex), expression); + if (expression is not LValueNode lValue) + { + throw new ParseException(Diagnostic + .Error("& symbol can only be used on lvalues") + .At(expression) + .Build()); + } + + expr = new AddressOfNode(GetTokensForNode(startIndex), lValue); break; } case Symbol.Minus: diff --git a/src/lang/Nub.Lang/Frontend/Typing/TypeChecker.cs b/src/lang/Nub.Lang/Frontend/Typing/TypeChecker.cs index 3f4aede..faf10f8 100644 --- a/src/lang/Nub.Lang/Frontend/Typing/TypeChecker.cs +++ b/src/lang/Nub.Lang/Frontend/Typing/TypeChecker.cs @@ -362,7 +362,6 @@ public class TypeChecker LiteralNode literal => TypeCheckLiteral(literal, expectedType), IdentifierNode identifier => TypeCheckIdentifier(identifier), BinaryExpressionNode binaryExpr => TypeCheckBinaryExpression(binaryExpr), - // CastNode cast => TypeCheckCast(cast), DereferenceNode dereference => TypeCheckDereference(dereference), FixedArrayInitializerNode fixedArray => TypeCheckFixedInitializerArray(fixedArray), FuncCallNode funcCallExpr => TypeCheckFuncCall(funcCallExpr, funcCallExpr), @@ -394,7 +393,7 @@ public class TypeChecker { if (literal.Kind == LiteralKind.Float) { - ReportWarning("Possible loss of precision when using float in integer context", literal); + ReportWarning("Float used in integer context. Everything after the '.' will be ignored", literal); } } @@ -517,13 +516,6 @@ public class TypeChecker } } - // private NubType? TypeCheckCast(CastNode cast) - // { - // TypeCheckExpression(cast.Expression, cast.TargetType); - // // TODO: Check if castable - // return cast.TargetType; - // } - private NubType? TypeCheckStructInitializer(StructInitializerNode structInit) { var initialized = new HashSet();