Simplify generator
This commit is contained in:
@@ -6,12 +6,10 @@ struct Human {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export func main(args: []^string) {
|
export func main(args: []^string) {
|
||||||
let human = [1]Human
|
let me = alloc Human {
|
||||||
|
|
||||||
human[0] = alloc Human {
|
|
||||||
name = "oliver"
|
name = "oliver"
|
||||||
age = 123
|
age = 32
|
||||||
}
|
}
|
||||||
|
|
||||||
c::printf("%s\n", human[1].name)
|
c::printf("%s is %d years old\n", me.name, me.age)
|
||||||
}
|
}
|
||||||
@@ -86,143 +86,175 @@ public class Generator
|
|||||||
return _builder.ToString();
|
return _builder.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string SQT(NubType type)
|
private enum TypeContext
|
||||||
{
|
{
|
||||||
switch (type)
|
Struct,
|
||||||
{
|
FuncDef,
|
||||||
case NubPrimitiveType primitiveType:
|
FuncCall,
|
||||||
{
|
|
||||||
switch (primitiveType.Kind)
|
|
||||||
{
|
|
||||||
case PrimitiveTypeKind.I64:
|
|
||||||
case PrimitiveTypeKind.U64:
|
|
||||||
case PrimitiveTypeKind.String:
|
|
||||||
case PrimitiveTypeKind.Any:
|
|
||||||
return "l";
|
|
||||||
case PrimitiveTypeKind.I32:
|
|
||||||
case PrimitiveTypeKind.U32:
|
|
||||||
case PrimitiveTypeKind.I16:
|
|
||||||
case PrimitiveTypeKind.U16:
|
|
||||||
case PrimitiveTypeKind.I8:
|
|
||||||
case PrimitiveTypeKind.U8:
|
|
||||||
case PrimitiveTypeKind.Bool:
|
|
||||||
return "w";
|
|
||||||
case PrimitiveTypeKind.F64:
|
|
||||||
return "d";
|
|
||||||
case PrimitiveTypeKind.F32:
|
|
||||||
return "s";
|
|
||||||
default:
|
|
||||||
throw new ArgumentOutOfRangeException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case NubStructType:
|
|
||||||
case NubPointerType:
|
|
||||||
case NubArrayType:
|
|
||||||
{
|
|
||||||
return "l";
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string EQT(NubType type)
|
private static string QBEType(NubType type, TypeContext context)
|
||||||
{
|
{
|
||||||
switch (type)
|
return context switch
|
||||||
{
|
{
|
||||||
case NubPrimitiveType primitiveType:
|
TypeContext.Struct => type switch
|
||||||
{
|
{
|
||||||
switch (primitiveType.Kind)
|
NubArrayType => "l", // TODO: Arrays in structs are pointers for now
|
||||||
|
NubPointerType => "l",
|
||||||
|
NubPrimitiveType primitiveType => primitiveType.Kind switch
|
||||||
{
|
{
|
||||||
case PrimitiveTypeKind.I64:
|
PrimitiveTypeKind.I64 => "l",
|
||||||
case PrimitiveTypeKind.U64:
|
PrimitiveTypeKind.I32 => "w",
|
||||||
case PrimitiveTypeKind.String:
|
PrimitiveTypeKind.I16 => "h",
|
||||||
return "l";
|
PrimitiveTypeKind.I8 => "b",
|
||||||
case PrimitiveTypeKind.Any:
|
PrimitiveTypeKind.U64 => "l",
|
||||||
case PrimitiveTypeKind.I32:
|
PrimitiveTypeKind.U32 => "w",
|
||||||
case PrimitiveTypeKind.U32:
|
PrimitiveTypeKind.U16 => "h",
|
||||||
return "w";
|
PrimitiveTypeKind.U8 => "b",
|
||||||
case PrimitiveTypeKind.I16:
|
PrimitiveTypeKind.F64 => "d",
|
||||||
case PrimitiveTypeKind.U16:
|
PrimitiveTypeKind.F32 => "s",
|
||||||
return "h";
|
PrimitiveTypeKind.Bool => "w",
|
||||||
case PrimitiveTypeKind.I8:
|
PrimitiveTypeKind.String => "l", // TODO: Strings in structs are pointers for now
|
||||||
case PrimitiveTypeKind.U8:
|
PrimitiveTypeKind.Any => throw new NotSupportedException("any type cannot be used in structs"),
|
||||||
return "b";
|
_ => throw new ArgumentOutOfRangeException()
|
||||||
case PrimitiveTypeKind.Bool:
|
},
|
||||||
case PrimitiveTypeKind.F64:
|
NubStructType => throw new NotImplementedException(),
|
||||||
return "d";
|
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
||||||
case PrimitiveTypeKind.F32:
|
},
|
||||||
return "s";
|
TypeContext.FuncDef => type switch
|
||||||
default:
|
|
||||||
throw new ArgumentOutOfRangeException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case NubStructType nubCustomType:
|
|
||||||
{
|
{
|
||||||
return ":" + nubCustomType.Name;
|
NubArrayType => "l",
|
||||||
}
|
NubPointerType => "l",
|
||||||
case NubPointerType:
|
NubPrimitiveType primitiveType => primitiveType.Kind switch
|
||||||
case NubArrayType:
|
|
||||||
{
|
{
|
||||||
return "l";
|
PrimitiveTypeKind.I64 => "l",
|
||||||
}
|
PrimitiveTypeKind.I32 => "w",
|
||||||
default:
|
PrimitiveTypeKind.I16 => "sh",
|
||||||
|
PrimitiveTypeKind.I8 => "sb",
|
||||||
|
PrimitiveTypeKind.U64 => "l",
|
||||||
|
PrimitiveTypeKind.U32 => "w",
|
||||||
|
PrimitiveTypeKind.U16 => "uh",
|
||||||
|
PrimitiveTypeKind.U8 => "ub",
|
||||||
|
PrimitiveTypeKind.F64 => "d",
|
||||||
|
PrimitiveTypeKind.F32 => "s",
|
||||||
|
PrimitiveTypeKind.Bool => "w",
|
||||||
|
PrimitiveTypeKind.String => "l",
|
||||||
|
PrimitiveTypeKind.Any => throw new NotSupportedException("any type cannot be used in function definitions"),
|
||||||
|
_ => throw new ArgumentOutOfRangeException()
|
||||||
|
},
|
||||||
|
NubStructType structType => $":{structType.Namespace}_{structType.Name}",
|
||||||
|
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
||||||
|
},
|
||||||
|
TypeContext.FuncCall => type switch
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
NubArrayType => "l",
|
||||||
}
|
NubPointerType => "l",
|
||||||
}
|
NubPrimitiveType pointerType => pointerType.Kind switch
|
||||||
|
{
|
||||||
|
PrimitiveTypeKind.I64 => "l",
|
||||||
|
PrimitiveTypeKind.I32 => "w",
|
||||||
|
PrimitiveTypeKind.I16 => "sh",
|
||||||
|
PrimitiveTypeKind.I8 => "sb",
|
||||||
|
PrimitiveTypeKind.U64 => "l",
|
||||||
|
PrimitiveTypeKind.U32 => "w",
|
||||||
|
PrimitiveTypeKind.U16 => "uh",
|
||||||
|
PrimitiveTypeKind.U8 => "ub",
|
||||||
|
PrimitiveTypeKind.F64 => "d",
|
||||||
|
PrimitiveTypeKind.F32 => "s",
|
||||||
|
PrimitiveTypeKind.Bool => "w",
|
||||||
|
PrimitiveTypeKind.String => "l",
|
||||||
|
PrimitiveTypeKind.Any => "l",
|
||||||
|
_ => throw new ArgumentOutOfRangeException()
|
||||||
|
},
|
||||||
|
NubStructType structType => $":{structType.Namespace}_{structType.Name}",
|
||||||
|
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
||||||
|
},
|
||||||
|
_ => throw new ArgumentOutOfRangeException(nameof(context), context, null)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string FQT(NubType type)
|
private static string QBEStore(NubType type)
|
||||||
{
|
{
|
||||||
switch (type)
|
return $"store{type switch
|
||||||
{
|
{
|
||||||
case NubPrimitiveType primitiveType:
|
NubArrayType => "l",
|
||||||
|
NubPointerType => "l",
|
||||||
|
NubPrimitiveType primitiveType => primitiveType.Kind switch
|
||||||
{
|
{
|
||||||
switch (primitiveType.Kind)
|
PrimitiveTypeKind.I64 => "l",
|
||||||
{
|
PrimitiveTypeKind.I32 => "w",
|
||||||
case PrimitiveTypeKind.I64:
|
PrimitiveTypeKind.I16 => "h",
|
||||||
case PrimitiveTypeKind.U64:
|
PrimitiveTypeKind.I8 => "b",
|
||||||
case PrimitiveTypeKind.String:
|
PrimitiveTypeKind.U64 => "l",
|
||||||
case PrimitiveTypeKind.Any:
|
PrimitiveTypeKind.U32 => "w",
|
||||||
return "l";
|
PrimitiveTypeKind.U16 => "h",
|
||||||
case PrimitiveTypeKind.I32:
|
PrimitiveTypeKind.U8 => "b",
|
||||||
case PrimitiveTypeKind.U32:
|
PrimitiveTypeKind.F64 => "d",
|
||||||
return "w";
|
PrimitiveTypeKind.F32 => "s",
|
||||||
case PrimitiveTypeKind.I16:
|
PrimitiveTypeKind.Bool => "w",
|
||||||
return "sh";
|
PrimitiveTypeKind.String => "l",
|
||||||
case PrimitiveTypeKind.U16:
|
PrimitiveTypeKind.Any => throw new NotSupportedException("any type cannot be used in store instructions"),
|
||||||
return "uh";
|
_ => throw new ArgumentOutOfRangeException()
|
||||||
case PrimitiveTypeKind.I8:
|
},
|
||||||
return "sb";
|
NubStructType => "l",
|
||||||
case PrimitiveTypeKind.U8:
|
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
||||||
return "ub";
|
}}";
|
||||||
case PrimitiveTypeKind.Bool:
|
|
||||||
return "b";
|
|
||||||
case PrimitiveTypeKind.F64:
|
|
||||||
return "d";
|
|
||||||
case PrimitiveTypeKind.F32:
|
|
||||||
return "s";
|
|
||||||
default:
|
|
||||||
throw new ArgumentOutOfRangeException();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
case NubStructType nubCustomType:
|
private static string QBELoad(NubType type)
|
||||||
{
|
{
|
||||||
return ":" + nubCustomType.Name;
|
return $"load{type switch
|
||||||
}
|
|
||||||
case NubPointerType:
|
|
||||||
case NubArrayType:
|
|
||||||
{
|
{
|
||||||
return "l";
|
NubArrayType => "l",
|
||||||
}
|
NubPointerType => "l",
|
||||||
default:
|
NubPrimitiveType primitiveType => primitiveType.Kind switch
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
PrimitiveTypeKind.I64 => "l",
|
||||||
}
|
PrimitiveTypeKind.I32 => "w",
|
||||||
|
PrimitiveTypeKind.I16 => "sh",
|
||||||
|
PrimitiveTypeKind.I8 => "sb",
|
||||||
|
PrimitiveTypeKind.U64 => "l",
|
||||||
|
PrimitiveTypeKind.U32 => "w",
|
||||||
|
PrimitiveTypeKind.U16 => "uh",
|
||||||
|
PrimitiveTypeKind.U8 => "ub",
|
||||||
|
PrimitiveTypeKind.F64 => "d",
|
||||||
|
PrimitiveTypeKind.F32 => "s",
|
||||||
|
PrimitiveTypeKind.Bool => "w",
|
||||||
|
PrimitiveTypeKind.String => "l",
|
||||||
|
PrimitiveTypeKind.Any => throw new NotSupportedException("any type cannot be used in load instructions"),
|
||||||
|
_ => throw new ArgumentOutOfRangeException()
|
||||||
|
},
|
||||||
|
NubStructType => "l",
|
||||||
|
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
||||||
|
}}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string QBEAssign(NubType type)
|
||||||
|
{
|
||||||
|
return $"={type switch
|
||||||
|
{
|
||||||
|
NubArrayType => "l",
|
||||||
|
NubPointerType => "l",
|
||||||
|
NubPrimitiveType primitiveType => primitiveType.Kind switch
|
||||||
|
{
|
||||||
|
PrimitiveTypeKind.I64 => "l",
|
||||||
|
PrimitiveTypeKind.I32 => "w",
|
||||||
|
PrimitiveTypeKind.I16 => "w",
|
||||||
|
PrimitiveTypeKind.I8 => "w",
|
||||||
|
PrimitiveTypeKind.U64 => "l",
|
||||||
|
PrimitiveTypeKind.U32 => "w",
|
||||||
|
PrimitiveTypeKind.U16 => "w",
|
||||||
|
PrimitiveTypeKind.U8 => "w",
|
||||||
|
PrimitiveTypeKind.F64 => "d",
|
||||||
|
PrimitiveTypeKind.F32 => "s",
|
||||||
|
PrimitiveTypeKind.Bool => "w",
|
||||||
|
PrimitiveTypeKind.String => "l",
|
||||||
|
PrimitiveTypeKind.Any => throw new NotSupportedException("any type cannot be used in variables"),
|
||||||
|
_ => throw new ArgumentOutOfRangeException()
|
||||||
|
},
|
||||||
|
NubStructType => "l",
|
||||||
|
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
||||||
|
}}";
|
||||||
}
|
}
|
||||||
|
|
||||||
private int QbeTypeSize(NubType type)
|
private int QbeTypeSize(NubType type)
|
||||||
@@ -297,7 +329,7 @@ public class Generator
|
|||||||
_builder.Append("function ");
|
_builder.Append("function ");
|
||||||
if (node.ReturnType.HasValue)
|
if (node.ReturnType.HasValue)
|
||||||
{
|
{
|
||||||
_builder.Append($"{FQT(node.ReturnType.Value)} ");
|
_builder.Append($"{QBEType(node.ReturnType.Value, TypeContext.FuncDef)} ");
|
||||||
}
|
}
|
||||||
else if (!node.ReturnType.HasValue && node.Name == "main")
|
else if (!node.ReturnType.HasValue && node.Name == "main")
|
||||||
{
|
{
|
||||||
@@ -307,7 +339,7 @@ public class Generator
|
|||||||
_builder.Append('$');
|
_builder.Append('$');
|
||||||
_builder.Append(_funcNames[node]);
|
_builder.Append(_funcNames[node]);
|
||||||
|
|
||||||
var parameterStrings = node.Parameters.Select(parameter => parameter.Variadic ? "..." : $"{FQT(parameter.Type)} %{parameter.Name}");
|
var parameterStrings = node.Parameters.Select(parameter => parameter.Variadic ? "..." : $"{QBEType(parameter.Type, TypeContext.FuncDef)} %{parameter.Name}");
|
||||||
|
|
||||||
_builder.AppendLine($"({string.Join(", ", parameterStrings)}) {{");
|
_builder.AppendLine($"({string.Join(", ", parameterStrings)}) {{");
|
||||||
_builder.AppendLine("@start");
|
_builder.AppendLine("@start");
|
||||||
@@ -316,7 +348,7 @@ public class Generator
|
|||||||
{
|
{
|
||||||
var parameterName = parameter.Name;
|
var parameterName = parameter.Name;
|
||||||
|
|
||||||
switch (FQT(parameter.Type))
|
switch (QBEType(parameter.Type, TypeContext.FuncDef))
|
||||||
{
|
{
|
||||||
case "sb":
|
case "sb":
|
||||||
parameterName = GenVarName();
|
parameterName = GenVarName();
|
||||||
@@ -337,7 +369,7 @@ public class Generator
|
|||||||
}
|
}
|
||||||
|
|
||||||
var pointerName = GenVarName();
|
var pointerName = GenVarName();
|
||||||
_builder.AppendLine($" %{pointerName} ={SQT(parameter.Type)} alloc8 {QbeTypeSize(parameter.Type)}");
|
_builder.AppendLine($" %{pointerName} {QBEAssign(parameter.Type)} alloc8 {QbeTypeSize(parameter.Type)}");
|
||||||
_builder.AppendLine($" storel %{parameterName}, %{pointerName}");
|
_builder.AppendLine($" storel %{parameterName}, %{pointerName}");
|
||||||
|
|
||||||
_variables[parameter.Name] = new Variable
|
_variables[parameter.Name] = new Variable
|
||||||
@@ -347,6 +379,8 @@ public class Generator
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_builder.AppendLine();
|
||||||
|
|
||||||
GenerateBlock(node.Body);
|
GenerateBlock(node.Body);
|
||||||
|
|
||||||
if (node.Body.Statements.LastOrDefault() is not ReturnNode)
|
if (node.Body.Statements.LastOrDefault() is not ReturnNode)
|
||||||
@@ -370,7 +404,7 @@ public class Generator
|
|||||||
|
|
||||||
private void GenerateStructDefinition(StructDefinitionNode structDefinition)
|
private void GenerateStructDefinition(StructDefinitionNode structDefinition)
|
||||||
{
|
{
|
||||||
var fields = structDefinition.Fields.Select(f => EQT(f.Type));
|
var fields = structDefinition.Fields.Select(f => QBEType(f.Type, TypeContext.Struct));
|
||||||
_builder.AppendLine($"type :{structDefinition.Name} = {{ {string.Join(", ", fields)} }}");
|
_builder.AppendLine($"type :{structDefinition.Name} = {{ {string.Join(", ", fields)} }}");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -387,6 +421,9 @@ public class Generator
|
|||||||
case ContinueNode:
|
case ContinueNode:
|
||||||
GenerateContinue();
|
GenerateContinue();
|
||||||
break;
|
break;
|
||||||
|
case DereferenceAssignmentNode dereferenceAssignment:
|
||||||
|
GenerateDereferenceAssignment(dereferenceAssignment);
|
||||||
|
break;
|
||||||
case IfNode ifStatement:
|
case IfNode ifStatement:
|
||||||
GenerateIf(ifStatement);
|
GenerateIf(ifStatement);
|
||||||
break;
|
break;
|
||||||
@@ -439,7 +476,7 @@ public class Generator
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_builder.AppendLine($" store{SQT(arrayType.BaseType)} {value}, %{offsetName}");
|
_builder.AppendLine($" {QBEStore(arrayType.BaseType)} {value}, %{offsetName}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -465,6 +502,21 @@ public class Generator
|
|||||||
_codeIsReachable = false;
|
_codeIsReachable = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void GenerateDereferenceAssignment(DereferenceAssignmentNode dereferenceAssignment)
|
||||||
|
{
|
||||||
|
var location = GenerateExpression(dereferenceAssignment.Dereference.Expression);
|
||||||
|
var value = GenerateExpression(dereferenceAssignment.Value);
|
||||||
|
|
||||||
|
if (IsLargeType(dereferenceAssignment.Value.Type))
|
||||||
|
{
|
||||||
|
_builder.AppendLine($" blit {value}, {location}, {QbeTypeSize(dereferenceAssignment.Value.Type)}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_builder.AppendLine($" {QBEStore(dereferenceAssignment.Value.Type)} {value}, {location}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void GenerateIf(IfNode ifStatement)
|
private void GenerateIf(IfNode ifStatement)
|
||||||
{
|
{
|
||||||
var trueLabel = GenLabelName();
|
var trueLabel = GenLabelName();
|
||||||
@@ -532,16 +584,31 @@ public class Generator
|
|||||||
|
|
||||||
var type = variableDeclaration.ExplicitType.Value ?? variableDeclaration.Value.Value?.Type!;
|
var type = variableDeclaration.ExplicitType.Value ?? variableDeclaration.Value.Value?.Type!;
|
||||||
|
|
||||||
_builder.AppendLine($" %{pointerName} ={SQT(type)} alloc8 {QbeTypeSize(type)}");
|
_builder.AppendLine($" %{pointerName} {QBEAssign(type)} alloc8 {QbeTypeSize(type)}");
|
||||||
|
|
||||||
if (variableDeclaration.Value.HasValue)
|
if (variableDeclaration.Value.HasValue)
|
||||||
{
|
{
|
||||||
var result = GenerateExpression(variableDeclaration.Value.Value);
|
var result = GenerateExpression(variableDeclaration.Value.Value);
|
||||||
_builder.AppendLine($" storel {result}, %{pointerName}");
|
|
||||||
|
if (IsLargeType(type))
|
||||||
|
{
|
||||||
|
_builder.AppendLine($" blit {result}, %{pointerName}, {QbeTypeSize(type)}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_builder.AppendLine($" storel 0, %{pointerName}");
|
_builder.AppendLine($" {QBEStore(type)} {result}, %{pointerName}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (IsLargeType(type))
|
||||||
|
{
|
||||||
|
_builder.AppendLine($" blit 0, %{pointerName}, {QbeTypeSize(type)}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_builder.AppendLine($" {QBEStore(type)} 0, %{pointerName}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_variables[variableDeclaration.Name] = new Variable
|
_variables[variableDeclaration.Name] = new Variable
|
||||||
@@ -615,7 +682,7 @@ public class Generator
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
var outputName = GenVarName();
|
var outputName = GenVarName();
|
||||||
_builder.AppendLine($" %{outputName} ={SQT(arrayType)} load{SQT(arrayType)} %{resultPointerName}");
|
_builder.AppendLine($" %{outputName} {QBEAssign(arrayType)} {QBELoad(arrayType)} %{resultPointerName}");
|
||||||
return $"%{outputName}";
|
return $"%{outputName}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -666,7 +733,7 @@ public class Generator
|
|||||||
{
|
{
|
||||||
var result = GenerateExpression(dereference.Expression);
|
var result = GenerateExpression(dereference.Expression);
|
||||||
var outputName = GenVarName();
|
var outputName = GenVarName();
|
||||||
_builder.AppendLine($" %{outputName} ={SQT(dereference.Type)} load{SQT(dereference.Type)} {result}");
|
_builder.AppendLine($" %{outputName} {QBEAssign(dereference.Type)} {QBELoad(dereference.Type)} {result}");
|
||||||
return $"%{outputName}";
|
return $"%{outputName}";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1379,7 +1446,7 @@ public class Generator
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
var outputName = GenVarName();
|
var outputName = GenVarName();
|
||||||
_builder.AppendLine($" %{outputName} ={SQT(identifier.Type)} load{SQT(identifier.Type)} {variable.Pointer}");
|
_builder.AppendLine($" %{outputName} {QBEAssign(identifier.Type)} {QBELoad(identifier.Type)} {variable.Pointer}");
|
||||||
return $"%{outputName}";
|
return $"%{outputName}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1436,7 +1503,7 @@ public class Generator
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_builder.AppendLine($" store{SQT(field.Type)} {var}, %{offsetName}");
|
_builder.AppendLine($" {QBEStore(field.Type)} {var}, %{offsetName}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (field.Value.HasValue)
|
else if (field.Value.HasValue)
|
||||||
@@ -1451,7 +1518,7 @@ public class Generator
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_builder.AppendLine($" store{SQT(field.Type)} {var}, %{offsetName}");
|
_builder.AppendLine($" {QBEStore(field.Type)} {var}, %{offsetName}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1542,7 +1609,7 @@ public class Generator
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
var outputName = GenVarName();
|
var outputName = GenVarName();
|
||||||
_builder.AppendLine($" %{outputName} ={SQT(memberAccess.Type)} load{SQT(memberAccess.Type)} %{offsetName}");
|
_builder.AppendLine($" %{outputName} {QBEAssign(memberAccess.Type)} {QBELoad(memberAccess.Type)} %{offsetName}");
|
||||||
|
|
||||||
return $"%{outputName}";
|
return $"%{outputName}";
|
||||||
}
|
}
|
||||||
@@ -1556,8 +1623,6 @@ public class Generator
|
|||||||
|
|
||||||
private string GenerateFuncCall(FuncCallNode funcCall)
|
private string GenerateFuncCall(FuncCallNode funcCall)
|
||||||
{
|
{
|
||||||
var outputName = GenVarName();
|
|
||||||
|
|
||||||
var funcDefinition = LookupFuncSignature(funcCall.Namespace, funcCall.Name, funcCall.Parameters.Select(p => p.Type).ToList());
|
var funcDefinition = LookupFuncSignature(funcCall.Namespace, funcCall.Name, funcCall.Parameters.Select(p => p.Type).ToList());
|
||||||
if (funcDefinition == null)
|
if (funcDefinition == null)
|
||||||
{
|
{
|
||||||
@@ -1573,34 +1638,27 @@ public class Generator
|
|||||||
parameterStrings.Add("...");
|
parameterStrings.Add("...");
|
||||||
}
|
}
|
||||||
|
|
||||||
NubType expectedType;
|
|
||||||
if (i < funcDefinition.Parameters.Count)
|
|
||||||
{
|
|
||||||
expectedType = funcDefinition.Parameters[i].Type;
|
|
||||||
}
|
|
||||||
else if (funcDefinition.Parameters[^1].Variadic)
|
|
||||||
{
|
|
||||||
expectedType = funcDefinition.Parameters[^1].Type;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new Exception($"Parameters for func {funcCall} does not not match");
|
|
||||||
}
|
|
||||||
|
|
||||||
var parameter = funcCall.Parameters[i];
|
var parameter = funcCall.Parameters[i];
|
||||||
var result = GenerateExpression(parameter);
|
var result = GenerateExpression(parameter);
|
||||||
|
|
||||||
var qbeParameterType = SQT(expectedType.Equals(NubPrimitiveType.Any) ? parameter.Type : expectedType);
|
var qbeParameterType = QBEType(parameter.Type, TypeContext.FuncCall);
|
||||||
parameterStrings.Add($"{qbeParameterType} {result}");
|
parameterStrings.Add($"{qbeParameterType} {result}");
|
||||||
}
|
}
|
||||||
|
|
||||||
var funcName = _funcNames[funcDefinition];
|
var funcName = _funcNames[funcDefinition];
|
||||||
|
|
||||||
var call = $"call ${funcName}({string.Join(", ", parameterStrings)})";
|
if (funcDefinition.ReturnType.HasValue)
|
||||||
|
{
|
||||||
_builder.AppendLine($" %{outputName} ={SQT(funcCall.Type)} {call}");
|
var outputName = GenVarName();
|
||||||
|
_builder.AppendLine($" %{outputName} {QBEAssign(funcCall.Type)} call ${funcName}({string.Join(", ", parameterStrings)})");
|
||||||
return $"%{outputName}";
|
return $"%{outputName}";
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_builder.AppendLine($" call ${funcName}({string.Join(", ", parameterStrings)})");
|
||||||
|
return "this should never show up!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private string GenVarName()
|
private string GenVarName()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -223,24 +223,32 @@ public class Parser
|
|||||||
{
|
{
|
||||||
case Symbol.Assign:
|
case Symbol.Assign:
|
||||||
{
|
{
|
||||||
Next();
|
|
||||||
switch (expr)
|
switch (expr)
|
||||||
{
|
{
|
||||||
case MemberAccessNode memberAccess:
|
case MemberAccessNode memberAccess:
|
||||||
{
|
{
|
||||||
|
Next();
|
||||||
var value = ParseExpression();
|
var value = ParseExpression();
|
||||||
return new MemberAssignmentNode(GetTokensForNode(startIndex), memberAccess, value);
|
return new MemberAssignmentNode(GetTokensForNode(startIndex), memberAccess, value);
|
||||||
}
|
}
|
||||||
case ArrayIndexAccessNode arrayIndexAccess:
|
case ArrayIndexAccessNode arrayIndexAccess:
|
||||||
{
|
{
|
||||||
|
Next();
|
||||||
var value = ParseExpression();
|
var value = ParseExpression();
|
||||||
return new ArrayIndexAssignmentNode(GetTokensForNode(startIndex), arrayIndexAccess, value);
|
return new ArrayIndexAssignmentNode(GetTokensForNode(startIndex), arrayIndexAccess, value);
|
||||||
}
|
}
|
||||||
case IdentifierNode identifier:
|
case IdentifierNode identifier:
|
||||||
{
|
{
|
||||||
|
Next();
|
||||||
var value = ParseExpression();
|
var value = ParseExpression();
|
||||||
return new VariableAssignmentNode(GetTokensForNode(startIndex), identifier, value);
|
return new VariableAssignmentNode(GetTokensForNode(startIndex), identifier, value);
|
||||||
}
|
}
|
||||||
|
case DereferenceNode dereference:
|
||||||
|
{
|
||||||
|
Next();
|
||||||
|
var value = ParseExpression();
|
||||||
|
return new DereferenceAssignmentNode(GetTokensForNode(startIndex), dereference, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
using Nub.Lang.Frontend.Lexing;
|
||||||
|
using Nub.Lang.Frontend.Parsing.Expressions;
|
||||||
|
|
||||||
|
namespace Nub.Lang.Frontend.Parsing.Statements;
|
||||||
|
|
||||||
|
public class DereferenceAssignmentNode(IReadOnlyList<Token> tokens, DereferenceNode dereference, ExpressionNode value) : StatementNode(tokens)
|
||||||
|
{
|
||||||
|
public DereferenceNode Dereference { get; } = dereference;
|
||||||
|
public ExpressionNode Value { get; } = value;
|
||||||
|
}
|
||||||
@@ -138,6 +138,9 @@ public class TypeChecker
|
|||||||
case BreakNode:
|
case BreakNode:
|
||||||
case ContinueNode:
|
case ContinueNode:
|
||||||
break;
|
break;
|
||||||
|
case DereferenceAssignmentNode dereferenceAssignment:
|
||||||
|
TypeCheckDereferenceAssignment(dereferenceAssignment);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ReportError($"Unsupported statement type: {statement.GetType().Name}", statement);
|
ReportError($"Unsupported statement type: {statement.GetType().Name}", statement);
|
||||||
break;
|
break;
|
||||||
@@ -347,6 +350,19 @@ public class TypeChecker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void TypeCheckDereferenceAssignment(DereferenceAssignmentNode dereferenceAssignment)
|
||||||
|
{
|
||||||
|
var dereferenceType = TypeCheckExpression(dereferenceAssignment.Dereference);
|
||||||
|
if (dereferenceType == null) return;
|
||||||
|
var valueType = TypeCheckExpression(dereferenceAssignment.Value);
|
||||||
|
if (valueType == null) return;
|
||||||
|
|
||||||
|
if (!NubType.IsCompatibleWith(dereferenceType, valueType))
|
||||||
|
{
|
||||||
|
ReportError($"'{valueType}' is not assignable to type '{dereferenceType}'", dereferenceAssignment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private NubType? TypeCheckExpression(ExpressionNode expression)
|
private NubType? TypeCheckExpression(ExpressionNode expression)
|
||||||
{
|
{
|
||||||
var resultType = expression switch
|
var resultType = expression switch
|
||||||
|
|||||||
Reference in New Issue
Block a user