Simplify generator
This commit is contained in:
@@ -6,12 +6,10 @@ struct Human {
|
||||
}
|
||||
|
||||
export func main(args: []^string) {
|
||||
let human = [1]Human
|
||||
|
||||
human[0] = alloc Human {
|
||||
let me = alloc Human {
|
||||
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();
|
||||
}
|
||||
|
||||
private static string SQT(NubType type)
|
||||
private enum TypeContext
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case NubPrimitiveType primitiveType:
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
Struct,
|
||||
FuncDef,
|
||||
FuncCall,
|
||||
}
|
||||
|
||||
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:
|
||||
case PrimitiveTypeKind.U64:
|
||||
case PrimitiveTypeKind.String:
|
||||
return "l";
|
||||
case PrimitiveTypeKind.Any:
|
||||
case PrimitiveTypeKind.I32:
|
||||
case PrimitiveTypeKind.U32:
|
||||
return "w";
|
||||
case PrimitiveTypeKind.I16:
|
||||
case PrimitiveTypeKind.U16:
|
||||
return "h";
|
||||
case PrimitiveTypeKind.I8:
|
||||
case PrimitiveTypeKind.U8:
|
||||
return "b";
|
||||
case PrimitiveTypeKind.Bool:
|
||||
case PrimitiveTypeKind.F64:
|
||||
return "d";
|
||||
case PrimitiveTypeKind.F32:
|
||||
return "s";
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
case NubStructType nubCustomType:
|
||||
PrimitiveTypeKind.I64 => "l",
|
||||
PrimitiveTypeKind.I32 => "w",
|
||||
PrimitiveTypeKind.I16 => "h",
|
||||
PrimitiveTypeKind.I8 => "b",
|
||||
PrimitiveTypeKind.U64 => "l",
|
||||
PrimitiveTypeKind.U32 => "w",
|
||||
PrimitiveTypeKind.U16 => "h",
|
||||
PrimitiveTypeKind.U8 => "b",
|
||||
PrimitiveTypeKind.F64 => "d",
|
||||
PrimitiveTypeKind.F32 => "s",
|
||||
PrimitiveTypeKind.Bool => "w",
|
||||
PrimitiveTypeKind.String => "l", // TODO: Strings in structs are pointers for now
|
||||
PrimitiveTypeKind.Any => throw new NotSupportedException("any type cannot be used in structs"),
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
NubStructType => throw new NotImplementedException(),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
||||
},
|
||||
TypeContext.FuncDef => type switch
|
||||
{
|
||||
return ":" + nubCustomType.Name;
|
||||
}
|
||||
case NubPointerType:
|
||||
case NubArrayType:
|
||||
NubArrayType => "l",
|
||||
NubPointerType => "l",
|
||||
NubPrimitiveType primitiveType => primitiveType.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 => 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
|
||||
{
|
||||
return "l";
|
||||
}
|
||||
default:
|
||||
{
|
||||
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)
|
||||
{
|
||||
case PrimitiveTypeKind.I64:
|
||||
case PrimitiveTypeKind.U64:
|
||||
case PrimitiveTypeKind.String:
|
||||
case PrimitiveTypeKind.Any:
|
||||
return "l";
|
||||
case PrimitiveTypeKind.I32:
|
||||
case PrimitiveTypeKind.U32:
|
||||
return "w";
|
||||
case PrimitiveTypeKind.I16:
|
||||
return "sh";
|
||||
case PrimitiveTypeKind.U16:
|
||||
return "uh";
|
||||
case PrimitiveTypeKind.I8:
|
||||
return "sb";
|
||||
case PrimitiveTypeKind.U8:
|
||||
return "ub";
|
||||
case PrimitiveTypeKind.Bool:
|
||||
return "b";
|
||||
case PrimitiveTypeKind.F64:
|
||||
return "d";
|
||||
case PrimitiveTypeKind.F32:
|
||||
return "s";
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
case NubStructType nubCustomType:
|
||||
PrimitiveTypeKind.I64 => "l",
|
||||
PrimitiveTypeKind.I32 => "w",
|
||||
PrimitiveTypeKind.I16 => "h",
|
||||
PrimitiveTypeKind.I8 => "b",
|
||||
PrimitiveTypeKind.U64 => "l",
|
||||
PrimitiveTypeKind.U32 => "w",
|
||||
PrimitiveTypeKind.U16 => "h",
|
||||
PrimitiveTypeKind.U8 => "b",
|
||||
PrimitiveTypeKind.F64 => "d",
|
||||
PrimitiveTypeKind.F32 => "s",
|
||||
PrimitiveTypeKind.Bool => "w",
|
||||
PrimitiveTypeKind.String => "l",
|
||||
PrimitiveTypeKind.Any => throw new NotSupportedException("any type cannot be used in store instructions"),
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
NubStructType => "l",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
||||
}}";
|
||||
}
|
||||
|
||||
private static string QBELoad(NubType type)
|
||||
{
|
||||
return $"load{type switch
|
||||
{
|
||||
NubArrayType => "l",
|
||||
NubPointerType => "l",
|
||||
NubPrimitiveType primitiveType => primitiveType.Kind switch
|
||||
{
|
||||
return ":" + nubCustomType.Name;
|
||||
}
|
||||
case NubPointerType:
|
||||
case NubArrayType:
|
||||
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
|
||||
{
|
||||
return "l";
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
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)
|
||||
@@ -297,7 +329,7 @@ public class Generator
|
||||
_builder.Append("function ");
|
||||
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")
|
||||
{
|
||||
@@ -307,7 +339,7 @@ public class Generator
|
||||
_builder.Append('$');
|
||||
_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("@start");
|
||||
@@ -316,7 +348,7 @@ public class Generator
|
||||
{
|
||||
var parameterName = parameter.Name;
|
||||
|
||||
switch (FQT(parameter.Type))
|
||||
switch (QBEType(parameter.Type, TypeContext.FuncDef))
|
||||
{
|
||||
case "sb":
|
||||
parameterName = GenVarName();
|
||||
@@ -337,7 +369,7 @@ public class Generator
|
||||
}
|
||||
|
||||
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}");
|
||||
|
||||
_variables[parameter.Name] = new Variable
|
||||
@@ -347,6 +379,8 @@ public class Generator
|
||||
};
|
||||
}
|
||||
|
||||
_builder.AppendLine();
|
||||
|
||||
GenerateBlock(node.Body);
|
||||
|
||||
if (node.Body.Statements.LastOrDefault() is not ReturnNode)
|
||||
@@ -370,7 +404,7 @@ public class Generator
|
||||
|
||||
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)} }}");
|
||||
}
|
||||
|
||||
@@ -387,6 +421,9 @@ public class Generator
|
||||
case ContinueNode:
|
||||
GenerateContinue();
|
||||
break;
|
||||
case DereferenceAssignmentNode dereferenceAssignment:
|
||||
GenerateDereferenceAssignment(dereferenceAssignment);
|
||||
break;
|
||||
case IfNode ifStatement:
|
||||
GenerateIf(ifStatement);
|
||||
break;
|
||||
@@ -439,7 +476,7 @@ public class Generator
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
var trueLabel = GenLabelName();
|
||||
@@ -532,16 +584,31 @@ public class Generator
|
||||
|
||||
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)
|
||||
{
|
||||
var result = GenerateExpression(variableDeclaration.Value.Value);
|
||||
_builder.AppendLine($" storel {result}, %{pointerName}");
|
||||
|
||||
if (IsLargeType(type))
|
||||
{
|
||||
_builder.AppendLine($" blit {result}, %{pointerName}, {QbeTypeSize(type)}");
|
||||
}
|
||||
else
|
||||
{
|
||||
_builder.AppendLine($" {QBEStore(type)} {result}, %{pointerName}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_builder.AppendLine($" storel 0, %{pointerName}");
|
||||
if (IsLargeType(type))
|
||||
{
|
||||
_builder.AppendLine($" blit 0, %{pointerName}, {QbeTypeSize(type)}");
|
||||
}
|
||||
else
|
||||
{
|
||||
_builder.AppendLine($" {QBEStore(type)} 0, %{pointerName}");
|
||||
}
|
||||
}
|
||||
|
||||
_variables[variableDeclaration.Name] = new Variable
|
||||
@@ -615,7 +682,7 @@ public class Generator
|
||||
else
|
||||
{
|
||||
var outputName = GenVarName();
|
||||
_builder.AppendLine($" %{outputName} ={SQT(arrayType)} load{SQT(arrayType)} %{resultPointerName}");
|
||||
_builder.AppendLine($" %{outputName} {QBEAssign(arrayType)} {QBELoad(arrayType)} %{resultPointerName}");
|
||||
return $"%{outputName}";
|
||||
}
|
||||
}
|
||||
@@ -666,7 +733,7 @@ public class Generator
|
||||
{
|
||||
var result = GenerateExpression(dereference.Expression);
|
||||
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}";
|
||||
}
|
||||
|
||||
@@ -1379,7 +1446,7 @@ public class Generator
|
||||
else
|
||||
{
|
||||
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}";
|
||||
}
|
||||
}
|
||||
@@ -1436,7 +1503,7 @@ public class Generator
|
||||
}
|
||||
else
|
||||
{
|
||||
_builder.AppendLine($" store{SQT(field.Type)} {var}, %{offsetName}");
|
||||
_builder.AppendLine($" {QBEStore(field.Type)} {var}, %{offsetName}");
|
||||
}
|
||||
}
|
||||
else if (field.Value.HasValue)
|
||||
@@ -1451,7 +1518,7 @@ public class Generator
|
||||
}
|
||||
else
|
||||
{
|
||||
_builder.AppendLine($" store{SQT(field.Type)} {var}, %{offsetName}");
|
||||
_builder.AppendLine($" {QBEStore(field.Type)} {var}, %{offsetName}");
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1542,7 +1609,7 @@ public class Generator
|
||||
else
|
||||
{
|
||||
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}";
|
||||
}
|
||||
@@ -1556,8 +1623,6 @@ public class Generator
|
||||
|
||||
private string GenerateFuncCall(FuncCallNode funcCall)
|
||||
{
|
||||
var outputName = GenVarName();
|
||||
|
||||
var funcDefinition = LookupFuncSignature(funcCall.Namespace, funcCall.Name, funcCall.Parameters.Select(p => p.Type).ToList());
|
||||
if (funcDefinition == null)
|
||||
{
|
||||
@@ -1573,33 +1638,26 @@ public class Generator
|
||||
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 result = GenerateExpression(parameter);
|
||||
|
||||
var qbeParameterType = SQT(expectedType.Equals(NubPrimitiveType.Any) ? parameter.Type : expectedType);
|
||||
var qbeParameterType = QBEType(parameter.Type, TypeContext.FuncCall);
|
||||
parameterStrings.Add($"{qbeParameterType} {result}");
|
||||
}
|
||||
|
||||
var funcName = _funcNames[funcDefinition];
|
||||
|
||||
var call = $"call ${funcName}({string.Join(", ", parameterStrings)})";
|
||||
|
||||
_builder.AppendLine($" %{outputName} ={SQT(funcCall.Type)} {call}");
|
||||
return $"%{outputName}";
|
||||
if (funcDefinition.ReturnType.HasValue)
|
||||
{
|
||||
var outputName = GenVarName();
|
||||
_builder.AppendLine($" %{outputName} {QBEAssign(funcCall.Type)} call ${funcName}({string.Join(", ", parameterStrings)})");
|
||||
return $"%{outputName}";
|
||||
}
|
||||
else
|
||||
{
|
||||
_builder.AppendLine($" call ${funcName}({string.Join(", ", parameterStrings)})");
|
||||
return "this should never show up!";
|
||||
}
|
||||
}
|
||||
|
||||
private string GenVarName()
|
||||
|
||||
@@ -223,24 +223,32 @@ public class Parser
|
||||
{
|
||||
case Symbol.Assign:
|
||||
{
|
||||
Next();
|
||||
switch (expr)
|
||||
{
|
||||
case MemberAccessNode memberAccess:
|
||||
{
|
||||
Next();
|
||||
var value = ParseExpression();
|
||||
return new MemberAssignmentNode(GetTokensForNode(startIndex), memberAccess, value);
|
||||
}
|
||||
case ArrayIndexAccessNode arrayIndexAccess:
|
||||
{
|
||||
Next();
|
||||
var value = ParseExpression();
|
||||
return new ArrayIndexAssignmentNode(GetTokensForNode(startIndex), arrayIndexAccess, value);
|
||||
}
|
||||
case IdentifierNode identifier:
|
||||
{
|
||||
Next();
|
||||
var value = ParseExpression();
|
||||
return new VariableAssignmentNode(GetTokensForNode(startIndex), identifier, value);
|
||||
}
|
||||
case DereferenceNode dereference:
|
||||
{
|
||||
Next();
|
||||
var value = ParseExpression();
|
||||
return new DereferenceAssignmentNode(GetTokensForNode(startIndex), dereference, value);
|
||||
}
|
||||
}
|
||||
|
||||
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 ContinueNode:
|
||||
break;
|
||||
case DereferenceAssignmentNode dereferenceAssignment:
|
||||
TypeCheckDereferenceAssignment(dereferenceAssignment);
|
||||
break;
|
||||
default:
|
||||
ReportError($"Unsupported statement type: {statement.GetType().Name}", statement);
|
||||
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)
|
||||
{
|
||||
var resultType = expression switch
|
||||
|
||||
Reference in New Issue
Block a user