improve addressof

This commit is contained in:
nub31
2025-06-08 13:54:10 +02:00
parent 6ea9cc0d54
commit 72eb3c89d8
12 changed files with 131 additions and 668 deletions

View File

@@ -5,15 +5,19 @@ struct Human {
} }
export func main(args: []^string): i64 { export func main(args: []^string): i64 {
let x = [3]f64 let age: u64 = 23
x[0] = 1 let me = alloc Human {
x[1] = 2 age = &age
x[2] = 3 }
c::printf("%f\n", x[0]) me.age^ = 24.5
c::printf("%f\n", x[1])
c::printf("%f\n", x[2]) test(me.age^)
return 0 return 0
} }
func test(me: u64) {
c::printf("%d\n", me)
}

View File

@@ -49,7 +49,7 @@ error = error || typeCheckResult.HasErrors;
if (error) return 1; if (error) return 1;
var generator = new Generator(); var generator = new QBEGenerator();
var result = generator.Generate(files); var result = generator.Generate(files);
Console.Out.Write(result); Console.Out.Write(result);

View File

@@ -10,7 +10,7 @@ using Nub.Lang.Frontend.Typing;
namespace Nub.Lang.Frontend.Generation; namespace Nub.Lang.Frontend.Generation;
public class Generator public class QBEGenerator
{ {
private const string OutOfBoundsMessage = "Index is out of bounds\\n"; private const string OutOfBoundsMessage = "Index is out of bounds\\n";
@@ -297,7 +297,7 @@ public class Generator
foreach (var parameter in node.Parameters) foreach (var parameter in node.Parameters)
{ {
var parameterName = parameter.Name; var parameterName = "%" + parameter.Name;
if (parameter.Type is NubPrimitiveType primitiveType) if (parameter.Type is NubPrimitiveType primitiveType)
{ {
@@ -319,24 +319,18 @@ public class Generator
parameterName = GenVarName(); parameterName = GenVarName();
_builder.AppendLine($" {parameterName} =w extub %{parameter.Name}"); _builder.AppendLine($" {parameterName} =w extub %{parameter.Name}");
break; break;
default:
throw new ArgumentOutOfRangeException();
} }
} }
_variables[parameter.Name] = parameterName; _variables[parameter.Name] = parameterName;
} }
_builder.AppendLine();
GenerateBlock(node.Body); GenerateBlock(node.Body);
if (node.Body.Statements.LastOrDefault() is not ReturnNode) if (node.Body.Statements.LastOrDefault() is not ReturnNode)
{ {
if (node.ReturnType is NubVoidType) if (node.ReturnType is NubVoidType)
{ {
_builder.AppendLine();
_builder.AppendLine(" # Implicit return");
_builder.AppendLine(" ret"); _builder.AppendLine(" ret");
} }
} }
@@ -436,17 +430,10 @@ public class Generator
var adjustedIndex = GenVarName(); var adjustedIndex = GenVarName();
_builder.AppendLine($" {adjustedIndex} =l mul {index}, {SizeOf(arrayType.ElementType)}"); _builder.AppendLine($" {adjustedIndex} =l mul {index}, {SizeOf(arrayType.ElementType)}");
var offsetName = GenVarName(); var pointer = GenVarName();
_builder.AppendLine($" {offsetName} =l add {startName}, {adjustedIndex}"); _builder.AppendLine($" {pointer} =l add {startName}, {adjustedIndex}");
if (IsLargeType(arrayType.ElementType)) GenerateCopy(arrayType.ElementType, value, pointer);
{
_builder.AppendLine($" blit {value}, {offsetName}, {SizeOf(arrayType.ElementType)}");
}
else
{
_builder.AppendLine($" {QBEStore(arrayType.ElementType)} {value}, {offsetName}");
}
break; break;
} }
case NubFixedArrayType fixedArrayType: case NubFixedArrayType fixedArrayType:
@@ -457,17 +444,10 @@ public class Generator
var adjustedIndex = GenVarName(); var adjustedIndex = GenVarName();
_builder.AppendLine($" {adjustedIndex} =l mul {index}, {SizeOf(fixedArrayType.ElementType)}"); _builder.AppendLine($" {adjustedIndex} =l mul {index}, {SizeOf(fixedArrayType.ElementType)}");
var offsetName = GenVarName(); var pointer = GenVarName();
_builder.AppendLine($" {offsetName} =l add {startName}, {adjustedIndex}"); _builder.AppendLine($" {pointer} =l add {startName}, {adjustedIndex}");
if (IsLargeType(fixedArrayType.ElementType)) GenerateCopy(fixedArrayType.ElementType, value, pointer);
{
_builder.AppendLine($" blit {value}, {offsetName}, {SizeOf(fixedArrayType.ElementType)}");
}
else
{
_builder.AppendLine($" {QBEStore(fixedArrayType.ElementType)} {value}, {offsetName}");
}
break; break;
} }
default: default:
@@ -501,17 +481,9 @@ public class Generator
private void GenerateDereferenceAssignment(DereferenceAssignmentNode dereferenceAssignment) private void GenerateDereferenceAssignment(DereferenceAssignmentNode dereferenceAssignment)
{ {
var location = GenerateExpression(dereferenceAssignment.Dereference.Expression); var pointer = GenerateExpression(dereferenceAssignment.Dereference.Expression);
var value = GenerateExpression(dereferenceAssignment.Value); var value = GenerateExpression(dereferenceAssignment.Value);
GenerateCopy(dereferenceAssignment.Value.Type, value, pointer);
if (IsLargeType(dereferenceAssignment.Value.Type))
{
_builder.AppendLine($" blit {value}, {location}, {SizeOf(dereferenceAssignment.Value.Type)}");
}
else
{
_builder.AppendLine($" {QBEStore(dereferenceAssignment.Value.Type)} {value}, {location}");
}
} }
private void GenerateIf(IfNode ifStatement) private void GenerateIf(IfNode ifStatement)
@@ -547,20 +519,13 @@ public class Generator
var offset = LookupMemberOffset(structDefinition, memberAssignment.MemberAccess.Member); var offset = LookupMemberOffset(structDefinition, memberAssignment.MemberAccess.Member);
var item = GenerateExpression(memberAssignment.MemberAccess.Expression); 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); var value = GenerateExpression(memberAssignment.Value);
if (IsLargeType(memberAssignment.Value.Type)) GenerateCopy(memberAssignment.Value.Type, value, pointer);
{
_builder.AppendLine($" blit {value}, {offsetName}, {SizeOf(memberAssignment.Value.Type)}");
}
else
{
_builder.AppendLine($" {QBEStore(memberAssignment.Value.Type)} {value}, {offsetName}");
}
} }
private void GenerateReturn(ReturnNode @return) private void GenerateReturn(ReturnNode @return)
@@ -575,48 +540,32 @@ public class Generator
_builder.AppendLine(" ret"); _builder.AppendLine(" ret");
} }
} }
private void GenerateVariableAssignment(VariableAssignmentNode variableAssignment) private void GenerateVariableAssignment(VariableAssignmentNode variableAssignment)
{ {
var result = GenerateExpression(variableAssignment.Value); var value = GenerateExpression(variableAssignment.Value);
_builder.AppendLine($" storel {result}, {_variables[variableAssignment.Identifier.Identifier]}"); var pointer = _variables[variableAssignment.Identifier.Identifier];
GenerateCopy(variableAssignment.Value.Type, value, pointer);
} }
private void GenerateVariableDeclaration(VariableDeclarationNode variableDeclaration) private void GenerateVariableDeclaration(VariableDeclarationNode variableDeclaration)
{ {
var type = variableDeclaration.ExplicitType.Value ?? variableDeclaration.Value.Value?.Type!; var type = variableDeclaration.ExplicitType.Value ?? variableDeclaration.Value.Value!.Type;
var pointer = GenVarName();
string pointerName; _builder.AppendLine($" {pointer} =l alloc8 {SizeOf(type)}");
if (variableDeclaration.Value.HasValue) if (variableDeclaration.Value.HasValue)
{ {
var result = GenerateExpression(variableDeclaration.Value.Value); var value = GenerateExpression(variableDeclaration.Value.Value);
if (IsLargeType(type)) GenerateCopy(variableDeclaration.Value.Value.Type, value, pointer);
{
pointerName = result;
}
else
{
pointerName = GenVarName();
_builder.AppendLine($" {pointerName} =l alloc8 {SizeOf(type)}");
_builder.AppendLine($" {QBEStore(type)} {result}, {pointerName}");
}
} }
else else
{ {
pointerName = GenVarName(); var pointerName = GenVarName();
_builder.AppendLine($" {pointerName} =l alloc8 {SizeOf(type)}"); _variables[variableDeclaration.Name] = pointerName;
if (IsLargeType(type))
{
_builder.AppendLine($" call $nub_memset(l {pointerName}, ub 0, l {SizeOf(type)})");
}
else
{
_builder.AppendLine($" {QBEStore(type)} 0, {pointerName}");
}
} }
_variables[variableDeclaration.Name] = pointerName; _variables[variableDeclaration.Name] = pointer;
} }
private void GenerateWhile(WhileNode whileStatement) private void GenerateWhile(WhileNode whileStatement)
@@ -645,10 +594,9 @@ public class Generator
return expression switch return expression switch
{ {
AddressOfNode addressOf => GenerateAddressOf(addressOf), AddressOfNode addressOf => GenerateAddressOf(addressOf),
ArrayIndexAccessNode arrayIndex => GenerateArrayIndex(arrayIndex), ArrayIndexAccessNode arrayIndex => GenerateArrayAccessIndex(arrayIndex),
ArrayInitializerNode arrayInitializer => GenerateArrayInitializer(arrayInitializer), ArrayInitializerNode arrayInitializer => GenerateArrayInitializer(arrayInitializer),
BinaryExpressionNode binaryExpression => GenerateBinaryExpression(binaryExpression), BinaryExpressionNode binaryExpression => GenerateBinaryExpression(binaryExpression),
// CastNode cast => GenerateCast(cast),
DereferenceNode dereference => GenerateDereference(dereference), DereferenceNode dereference => GenerateDereference(dereference),
FixedArrayInitializerNode fixedArrayInitializer => GenerateFixedArrayInitializer(fixedArrayInitializer), FixedArrayInitializerNode fixedArrayInitializer => GenerateFixedArrayInitializer(fixedArrayInitializer),
FuncCallNode funcCallExpression => GenerateFuncCall(funcCallExpression), 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 array = GenerateExpression(arrayIndexAccess.Array);
var index = GenerateExpression(arrayIndexAccess.Index); var index = GenerateExpression(arrayIndexAccess.Index);
GenerateArrayBoundsCheck(array, index); GenerateArrayBoundsCheck(array, index);
switch (arrayIndexAccess.Array.Type) switch (arrayIndexAccess.Array.Type)
{ {
case NubArrayType arrayType: case NubArrayType arrayType:
@@ -677,17 +625,7 @@ public class Generator
_builder.AppendLine($" {offsetPointerName} =l mul {index}, {SizeOf(arrayType.ElementType)}"); _builder.AppendLine($" {offsetPointerName} =l mul {index}, {SizeOf(arrayType.ElementType)}");
var resultPointerName = GenVarName(); var resultPointerName = GenVarName();
_builder.AppendLine($" {resultPointerName} =l add {firstItemPointerName}, {offsetPointerName}"); _builder.AppendLine($" {resultPointerName} =l add {firstItemPointerName}, {offsetPointerName}");
return resultPointerName;
if (IsLargeType(arrayType.ElementType))
{
return resultPointerName;
}
else
{
var outputName = GenVarName();
_builder.AppendLine($" {outputName} {QBEAssign(arrayType.ElementType)} {QBELoad(arrayType.ElementType)} {resultPointerName}");
return outputName;
}
} }
case NubFixedArrayType fixedArrayType: case NubFixedArrayType fixedArrayType:
{ {
@@ -697,17 +635,7 @@ public class Generator
_builder.AppendLine($" {offsetPointerName} =l mul {index}, {SizeOf(fixedArrayType.ElementType)}"); _builder.AppendLine($" {offsetPointerName} =l mul {index}, {SizeOf(fixedArrayType.ElementType)}");
var resultPointerName = GenVarName(); var resultPointerName = GenVarName();
_builder.AppendLine($" {resultPointerName} =l add {firstItemPointerName}, {offsetPointerName}"); _builder.AppendLine($" {resultPointerName} =l add {firstItemPointerName}, {offsetPointerName}");
return resultPointerName;
if (IsLargeType(fixedArrayType.ElementType))
{
return resultPointerName;
}
else
{
var outputName = GenVarName();
_builder.AppendLine($" {outputName} {QBEAssign(fixedArrayType.ElementType)} {QBELoad(fixedArrayType.ElementType)} {resultPointerName}");
return outputName;
}
} }
default: 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) private void GenerateArrayBoundsCheck(string array, string index)
{ {
@@ -768,30 +712,18 @@ public class Generator
private string GenerateAddressOf(AddressOfNode addressOf) private string GenerateAddressOf(AddressOfNode addressOf)
{ {
var result = GenerateExpression(addressOf.Expression); switch (addressOf.Expression)
var outputName = GenVarName();
switch (addressOf.Expression.Type)
{ {
case NubPointerType: case ArrayIndexAccessNode arrayIndexAccess:
case NubStructType: return GenerateArrayIndexPointer(arrayIndexAccess);
case NubPrimitiveType { Kind: PrimitiveTypeKind.I64 }: case DereferenceNode dereference:
case NubPrimitiveType { Kind: PrimitiveTypeKind.F64 }: return GenerateExpression(dereference.Expression);
case NubPrimitiveType { Kind: PrimitiveTypeKind.U64 }: case IdentifierNode identifier:
_builder.AppendLine($" {outputName} =l alloc8 8"); return _variables[identifier.Identifier];
_builder.AppendLine($" storel {result}, {outputName}"); case MemberAccessNode memberAccess:
return outputName; return GenerateMemberAccessPointer(memberAccess);
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;
default: 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"); 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) private string GenerateIdentifier(IdentifierNode identifier)
{ {
var variable = _variables[identifier.Identifier]; return _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;
}
} }
private string GenerateLiteral(LiteralNode literal) private string GenerateLiteral(LiteralNode literal)
@@ -1534,33 +1013,17 @@ public class Generator
if (structInitializer.Initializers.TryGetValue(field.Name, out var fieldValue)) if (structInitializer.Initializers.TryGetValue(field.Name, out var fieldValue))
{ {
var var = GenerateExpression(fieldValue); var value = GenerateExpression(fieldValue);
var offsetName = GenVarName(); var pointer = GenVarName();
_builder.AppendLine($" {offsetName} =l add {structVar}, {offset}"); _builder.AppendLine($" {pointer} =l add {structVar}, {offset}");
GenerateCopy(field.Type, value, pointer);
if (IsLargeType(field.Type))
{
_builder.AppendLine($" blit {var}, {offsetName}, {SizeOf(field.Type)}");
}
else
{
_builder.AppendLine($" {QBEStore(field.Type)} {var}, {offsetName}");
}
} }
else if (field.Value.HasValue) else if (field.Value.HasValue)
{ {
var var = GenerateExpression(field.Value.Value); var value = GenerateExpression(field.Value.Value);
var offsetName = GenVarName(); var pointer = GenVarName();
_builder.AppendLine($" {offsetName} =l add {structVar}, {offset}"); _builder.AppendLine($" {pointer} =l add {structVar}, {offset}");
GenerateCopy(field.Type, value, pointer);
if (IsLargeType(field.Type))
{
_builder.AppendLine($" blit {var}, {offsetName}, {SizeOf(field.Type)}");
}
else
{
_builder.AppendLine($" {QBEStore(field.Type)} {var}, {offsetName}");
}
} }
else else
{ {
@@ -1618,22 +1081,19 @@ public class Generator
throw new NotSupportedException($"Unary operator {unaryExpression.Operator} for type {unaryExpression.Operand.Type} not supported"); 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); var item = GenerateExpression(memberAccess.Expression);
switch (memberAccess.Expression.Type) switch (memberAccess.Expression.Type)
{ {
case NubArrayType: case NubArrayType:
{ {
if (memberAccess.Member == "count") if (memberAccess.Member == "count")
{ {
var outputName = GenVarName(); return item;
_builder.AppendLine($" {outputName} =l loadl {item}");
return outputName;
} }
throw new ArgumentOutOfRangeException(nameof(memberAccess.Member)); throw new UnreachableException(nameof(memberAccess.Member));
} }
case NubStructType structType: case NubStructType structType:
{ {
@@ -1642,26 +1102,31 @@ public class Generator
var offsetName = GenVarName(); var offsetName = GenVarName();
_builder.AppendLine($" {offsetName} =l add {item}, {offset}"); _builder.AppendLine($" {offsetName} =l add {item}, {offset}");
return offsetName;
if (IsLargeType(memberAccess.Type))
{
return offsetName;
}
else
{
var outputName = GenVarName();
_builder.AppendLine($" {outputName} {QBEAssign(memberAccess.Type)} {QBELoad(memberAccess.Type)} {offsetName}");
return outputName;
}
} }
default: 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) private string GenerateFixedArrayInitializer(FixedArrayInitializerNode fixedArrayInitializer)
{ {
var capacityInBytes = SizeOf(fixedArrayInitializer.Type); 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() private string GenVarName()
{ {
return $"%v{++_variableIndex}"; return $"%v{++_variableIndex}";

View File

@@ -2,7 +2,7 @@ using Nub.Lang.Frontend.Lexing;
namespace Nub.Lang.Frontend.Parsing.Expressions; namespace Nub.Lang.Frontend.Parsing.Expressions;
public class AddressOfNode(IReadOnlyList<Token> tokens, ExpressionNode expression) : ExpressionNode(tokens) public class AddressOfNode(IReadOnlyList<Token> tokens, LValueNode expression) : ExpressionNode(tokens)
{ {
public ExpressionNode Expression { get; } = expression; public LValueNode Expression { get; } = expression;
} }

View File

@@ -2,7 +2,7 @@ using Nub.Lang.Frontend.Lexing;
namespace Nub.Lang.Frontend.Parsing.Expressions; namespace Nub.Lang.Frontend.Parsing.Expressions;
public class ArrayIndexAccessNode(IReadOnlyList<Token> tokens, ExpressionNode array, ExpressionNode index) : ExpressionNode(tokens) public class ArrayIndexAccessNode(IReadOnlyList<Token> tokens, ExpressionNode array, ExpressionNode index) : LValueNode(tokens)
{ {
public ExpressionNode Array { get; } = array; public ExpressionNode Array { get; } = array;
public ExpressionNode Index { get; } = index; public ExpressionNode Index { get; } = index;

View File

@@ -1,10 +0,0 @@
// using Nub.Lang.Frontend.Lexing;
// using Nub.Lang.Frontend.Typing;
//
// namespace Nub.Lang.Frontend.Parsing.Expressions;
//
// public class CastNode(IReadOnlyList<Token> tokens, NubType targetType, ExpressionNode expression) : ExpressionNode(tokens)
// {
// public NubType TargetType { get; } = targetType;
// public ExpressionNode Expression { get; } = expression;
// }

View File

@@ -2,7 +2,7 @@ using Nub.Lang.Frontend.Lexing;
namespace Nub.Lang.Frontend.Parsing.Expressions; namespace Nub.Lang.Frontend.Parsing.Expressions;
public class DereferenceNode(IReadOnlyList<Token> tokens, ExpressionNode expression) : ExpressionNode(tokens) public class DereferenceNode(IReadOnlyList<Token> tokens, ExpressionNode expression) : LValueNode(tokens)
{ {
public ExpressionNode Expression { get; } = expression; public ExpressionNode Expression { get; } = expression;
} }

View File

@@ -11,4 +11,6 @@ public abstract class ExpressionNode(IReadOnlyList<Token> tokens) : Node(tokens)
get => _type ?? throw new Exception("Tried to access expression type before type was populated"); get => _type ?? throw new Exception("Tried to access expression type before type was populated");
set => _type = value; set => _type = value;
} }
} }
public abstract class LValueNode(IReadOnlyList<Token> tokens) : ExpressionNode(tokens);

View File

@@ -2,7 +2,7 @@
namespace Nub.Lang.Frontend.Parsing.Expressions; namespace Nub.Lang.Frontend.Parsing.Expressions;
public class IdentifierNode(IReadOnlyList<Token> tokens, string identifier) : ExpressionNode(tokens) public class IdentifierNode(IReadOnlyList<Token> tokens, string identifier) : LValueNode(tokens)
{ {
public string Identifier { get; } = identifier; public string Identifier { get; } = identifier;

View File

@@ -2,7 +2,7 @@
namespace Nub.Lang.Frontend.Parsing.Expressions; namespace Nub.Lang.Frontend.Parsing.Expressions;
public class MemberAccessNode(IReadOnlyList<Token> tokens, ExpressionNode expression, string member) : ExpressionNode(tokens) public class MemberAccessNode(IReadOnlyList<Token> tokens, ExpressionNode expression, string member) : LValueNode(tokens)
{ {
public ExpressionNode Expression { get; } = expression; public ExpressionNode Expression { get; } = expression;
public string Member { get; } = member; public string Member { get; } = member;

View File

@@ -495,20 +495,18 @@ public class Parser
expr = expression; expr = expression;
break; 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: case Symbol.Ampersand:
{ {
var expression = ParsePrimaryExpression(); 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; break;
} }
case Symbol.Minus: case Symbol.Minus:

View File

@@ -362,7 +362,6 @@ public class TypeChecker
LiteralNode literal => TypeCheckLiteral(literal, expectedType), LiteralNode literal => TypeCheckLiteral(literal, expectedType),
IdentifierNode identifier => TypeCheckIdentifier(identifier), IdentifierNode identifier => TypeCheckIdentifier(identifier),
BinaryExpressionNode binaryExpr => TypeCheckBinaryExpression(binaryExpr), BinaryExpressionNode binaryExpr => TypeCheckBinaryExpression(binaryExpr),
// CastNode cast => TypeCheckCast(cast),
DereferenceNode dereference => TypeCheckDereference(dereference), DereferenceNode dereference => TypeCheckDereference(dereference),
FixedArrayInitializerNode fixedArray => TypeCheckFixedInitializerArray(fixedArray), FixedArrayInitializerNode fixedArray => TypeCheckFixedInitializerArray(fixedArray),
FuncCallNode funcCallExpr => TypeCheckFuncCall(funcCallExpr, funcCallExpr), FuncCallNode funcCallExpr => TypeCheckFuncCall(funcCallExpr, funcCallExpr),
@@ -394,7 +393,7 @@ public class TypeChecker
{ {
if (literal.Kind == LiteralKind.Float) 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) private NubType? TypeCheckStructInitializer(StructInitializerNode structInit)
{ {
var initialized = new HashSet<string>(); var initialized = new HashSet<string>();