...
This commit is contained in:
@@ -21,7 +21,6 @@ public class Generator
|
||||
private Stack<string> _continueLabels = [];
|
||||
private int _variableIndex;
|
||||
private int _labelIndex;
|
||||
private int _funcIndex;
|
||||
private bool _codeIsReachable = true;
|
||||
private Dictionary<IFuncSignature, string> _funcNames = [];
|
||||
|
||||
@@ -35,7 +34,6 @@ public class Generator
|
||||
_breakLabels = [];
|
||||
_continueLabels = [];
|
||||
_variableIndex = 0;
|
||||
_funcIndex = 0;
|
||||
_labelIndex = 0;
|
||||
_codeIsReachable = true;
|
||||
|
||||
@@ -45,12 +43,14 @@ public class Generator
|
||||
_builder.AppendLine();
|
||||
}
|
||||
|
||||
var localFuncIndex = 0;
|
||||
|
||||
foreach (var funcSignature in _sourceFiles.SelectMany(f => f.Definitions).OfType<IFuncSignature>())
|
||||
{
|
||||
switch (funcSignature)
|
||||
{
|
||||
case ExternFuncDefinitionNode externFuncDefinitionNode:
|
||||
_funcNames[funcSignature] = "$" + externFuncDefinitionNode.Name;
|
||||
_funcNames[funcSignature] = "$" + externFuncDefinitionNode.CallName;
|
||||
break;
|
||||
case LocalFuncDefinitionNode localFuncDefinitionNode:
|
||||
if (localFuncDefinitionNode.Exported)
|
||||
@@ -59,8 +59,7 @@ public class Generator
|
||||
}
|
||||
else
|
||||
{
|
||||
var funcName = GenFuncName();
|
||||
_funcNames[funcSignature] = funcName;
|
||||
_funcNames[funcSignature] = $"$func{++localFuncIndex}";
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -88,7 +87,6 @@ public class Generator
|
||||
|
||||
private enum TypeContext
|
||||
{
|
||||
Struct,
|
||||
FuncDef,
|
||||
FuncCall,
|
||||
}
|
||||
@@ -97,30 +95,6 @@ public class Generator
|
||||
{
|
||||
return context switch
|
||||
{
|
||||
TypeContext.Struct => type switch
|
||||
{
|
||||
NubArrayType => "l", // TODO: Arrays in structs are pointers for now
|
||||
NubPointerType => "l",
|
||||
NubPrimitiveType primitiveType => primitiveType.Kind switch
|
||||
{
|
||||
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
|
||||
{
|
||||
NubArrayType => "l",
|
||||
@@ -143,6 +117,7 @@ public class Generator
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
NubStructType structType => $":{structType.Namespace}_{structType.Name}",
|
||||
NubFixedArrayType => "l",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
||||
},
|
||||
TypeContext.FuncCall => type switch
|
||||
@@ -167,6 +142,7 @@ public class Generator
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
NubStructType structType => $":{structType.Namespace}_{structType.Name}",
|
||||
NubFixedArrayType => "l",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
||||
},
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(context), context, null)
|
||||
@@ -197,6 +173,7 @@ public class Generator
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
NubStructType => "l",
|
||||
NubFixedArrayType => "l",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
||||
}}";
|
||||
}
|
||||
@@ -225,6 +202,7 @@ public class Generator
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
NubStructType => "l",
|
||||
NubFixedArrayType => "l",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
||||
}}";
|
||||
}
|
||||
@@ -253,11 +231,12 @@ public class Generator
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
NubStructType => "l",
|
||||
NubFixedArrayType => "l",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
||||
}}";
|
||||
}
|
||||
|
||||
private int QbeTypeSize(NubType type)
|
||||
private int SizeOf(NubType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
@@ -291,16 +270,20 @@ public class Generator
|
||||
case NubStructType nubStructType:
|
||||
{
|
||||
var definition = LookupStructDefinition(nubStructType.Namespace, nubStructType.Name);
|
||||
return definition.Fields.Sum(f => QbeTypeSize(f.Type));
|
||||
return definition.Fields.Sum(f => SizeOf(f.Type));
|
||||
}
|
||||
case NubPointerType:
|
||||
case NubArrayType:
|
||||
{
|
||||
return 8;
|
||||
}
|
||||
case NubFixedArrayType nubFixedArrayType:
|
||||
{
|
||||
return SizeOf(nubFixedArrayType.ElementType) * nubFixedArrayType.Capacity;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
throw new UnreachableException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -313,6 +296,7 @@ public class Generator
|
||||
NubPointerType => false,
|
||||
NubPrimitiveType => false,
|
||||
NubStructType => true,
|
||||
NubFixedArrayType => true,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
||||
};
|
||||
}
|
||||
@@ -368,7 +352,7 @@ public class Generator
|
||||
}
|
||||
|
||||
var pointerName = GenVarName();
|
||||
_builder.AppendLine($" {pointerName} {QBEAssign(parameter.Type)} alloc8 {QbeTypeSize(parameter.Type)}");
|
||||
_builder.AppendLine($" {pointerName} {QBEAssign(parameter.Type)} alloc8 {SizeOf(parameter.Type)}");
|
||||
_builder.AppendLine($" storel %{parameterName}, {pointerName}");
|
||||
|
||||
_variables[parameter.Name] = new Variable
|
||||
@@ -403,8 +387,42 @@ public class Generator
|
||||
|
||||
private void GenerateStructDefinition(StructDefinitionNode structDefinition)
|
||||
{
|
||||
var fields = structDefinition.Fields.Select(f => QBEType(f.Type, TypeContext.Struct));
|
||||
_builder.AppendLine($"type :{structDefinition.Name} = {{ {string.Join(", ", fields)} }}");
|
||||
_builder.Append($"type :{structDefinition.Namespace}_{structDefinition.Name} = {{ ");
|
||||
foreach (var structDefinitionField in structDefinition.Fields)
|
||||
{
|
||||
var fieldDefinition = GenerateFieldType(structDefinitionField.Type);
|
||||
_builder.Append(fieldDefinition + ", ");
|
||||
}
|
||||
_builder.AppendLine("}");
|
||||
}
|
||||
|
||||
private string GenerateFieldType(NubType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
NubArrayType => "l",
|
||||
NubPointerType => "l",
|
||||
NubPrimitiveType primitiveType => primitiveType.Kind switch
|
||||
{
|
||||
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 structs"),
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
NubStructType structType => $":{structType.Namespace}_{structType.Name}",
|
||||
NubFixedArrayType fixedArrayType => $"b {SizeOf(fixedArrayType)}",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
||||
};
|
||||
}
|
||||
|
||||
private void GenerateStatement(StatementNode statement)
|
||||
@@ -451,31 +469,59 @@ public class Generator
|
||||
|
||||
private void GenerateArrayIndexAssignment(ArrayIndexAssignmentNode arrayIndexAssignment)
|
||||
{
|
||||
var arrayType = (NubArrayType)arrayIndexAssignment.ArrayIndexAccess.Array.Type;
|
||||
|
||||
var array = GenerateExpression(arrayIndexAssignment.ArrayIndexAccess.Array);
|
||||
var index = GenerateExpression(arrayIndexAssignment.ArrayIndexAccess.Index);
|
||||
|
||||
GenerateArrayBoundsCheck(array, index);
|
||||
|
||||
var value = GenerateExpression(arrayIndexAssignment.Value);
|
||||
|
||||
var startName = GenVarName();
|
||||
_builder.AppendLine($" {startName} =l add {array}, 8");
|
||||
|
||||
var adjustedIndex = GenVarName();
|
||||
_builder.AppendLine($" {adjustedIndex} =l mul {index}, {QbeTypeSize(arrayType.BaseType)}");
|
||||
|
||||
var offsetName = GenVarName();
|
||||
_builder.AppendLine($" {offsetName} =l add {startName}, {adjustedIndex}");
|
||||
|
||||
if (IsLargeType(arrayType.BaseType))
|
||||
switch (arrayIndexAssignment.ArrayIndexAccess.Array.Type)
|
||||
{
|
||||
_builder.AppendLine($" blit {value}, {offsetName}, {QbeTypeSize(arrayType.BaseType)}");
|
||||
}
|
||||
else
|
||||
{
|
||||
_builder.AppendLine($" {QBEStore(arrayType.BaseType)} {value}, {offsetName}");
|
||||
case NubArrayType arrayType:
|
||||
{
|
||||
var startName = GenVarName();
|
||||
_builder.AppendLine($" {startName} =l add {array}, 8");
|
||||
|
||||
var adjustedIndex = GenVarName();
|
||||
_builder.AppendLine($" {adjustedIndex} =l mul {index}, {SizeOf(arrayType.ElementType)}");
|
||||
|
||||
var offsetName = GenVarName();
|
||||
_builder.AppendLine($" {offsetName} =l add {startName}, {adjustedIndex}");
|
||||
|
||||
if (IsLargeType(arrayType.ElementType))
|
||||
{
|
||||
_builder.AppendLine($" blit {value}, {offsetName}, {SizeOf(arrayType.ElementType)}");
|
||||
}
|
||||
else
|
||||
{
|
||||
_builder.AppendLine($" {QBEStore(arrayType.ElementType)} {value}, {offsetName}");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NubFixedArrayType fixedArrayType:
|
||||
{
|
||||
var startName = GenVarName();
|
||||
_builder.AppendLine($" {startName} =l add {array}, 8");
|
||||
|
||||
var adjustedIndex = GenVarName();
|
||||
_builder.AppendLine($" {adjustedIndex} =l mul {index}, {SizeOf(fixedArrayType.ElementType)}");
|
||||
|
||||
var offsetName = GenVarName();
|
||||
_builder.AppendLine($" {offsetName} =l add {startName}, {adjustedIndex}");
|
||||
|
||||
if (IsLargeType(fixedArrayType.ElementType))
|
||||
{
|
||||
_builder.AppendLine($" blit {value}, {offsetName}, {SizeOf(fixedArrayType.ElementType)}");
|
||||
}
|
||||
else
|
||||
{
|
||||
_builder.AppendLine($" {QBEStore(fixedArrayType.ElementType)} {value}, {offsetName}");
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new UnreachableException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -508,7 +554,7 @@ public class Generator
|
||||
|
||||
if (IsLargeType(dereferenceAssignment.Value.Type))
|
||||
{
|
||||
_builder.AppendLine($" blit {value}, {location}, {QbeTypeSize(dereferenceAssignment.Value.Type)}");
|
||||
_builder.AppendLine($" blit {value}, {location}, {SizeOf(dereferenceAssignment.Value.Type)}");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -555,7 +601,14 @@ public class Generator
|
||||
|
||||
var value = GenerateExpression(memberAssignment.Value);
|
||||
|
||||
throw new NotImplementedException();
|
||||
if (IsLargeType(memberAssignment.Value.Type))
|
||||
{
|
||||
_builder.AppendLine($" blit {value}, {offsetName}, {SizeOf(memberAssignment.Value.Type)}");
|
||||
}
|
||||
else
|
||||
{
|
||||
_builder.AppendLine($" {QBEStore(memberAssignment.Value.Type)} {value}, {offsetName}");
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateReturn(ReturnNode @return)
|
||||
@@ -579,30 +632,31 @@ public class Generator
|
||||
|
||||
private void GenerateVariableDeclaration(VariableDeclarationNode variableDeclaration)
|
||||
{
|
||||
var pointerName = GenVarName();
|
||||
|
||||
var type = variableDeclaration.ExplicitType.Value ?? variableDeclaration.Value.Value?.Type!;
|
||||
|
||||
_builder.AppendLine($" {pointerName} {QBEAssign(type)} alloc8 {QbeTypeSize(type)}");
|
||||
|
||||
string pointerName;
|
||||
|
||||
if (variableDeclaration.Value.HasValue)
|
||||
{
|
||||
var result = GenerateExpression(variableDeclaration.Value.Value);
|
||||
|
||||
if (IsLargeType(type))
|
||||
{
|
||||
_builder.AppendLine($" blit {result}, {pointerName}, {QbeTypeSize(type)}");
|
||||
pointerName = result;
|
||||
}
|
||||
else
|
||||
{
|
||||
pointerName = GenVarName();
|
||||
_builder.AppendLine($" {pointerName} {QBEAssign(type)} alloc8 {SizeOf(type)}");
|
||||
_builder.AppendLine($" {QBEStore(type)} {result}, {pointerName}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pointerName = GenVarName();
|
||||
_builder.AppendLine($" {pointerName} {QBEAssign(type)} alloc8 {SizeOf(type)}");
|
||||
if (IsLargeType(type))
|
||||
{
|
||||
_builder.AppendLine($" blit 0, {pointerName}, {QbeTypeSize(type)}");
|
||||
_builder.AppendLine($" call $nub_memset(l {pointerName}, ub 0, l {SizeOf(type)})");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -648,6 +702,7 @@ public class Generator
|
||||
BinaryExpressionNode binaryExpression => GenerateBinaryExpression(binaryExpression),
|
||||
CastNode cast => GenerateCast(cast),
|
||||
DereferenceNode dereference => GenerateDereference(dereference),
|
||||
FixedArrayInitializerNode fixedArrayInitializer => GenerateFixedArrayInitializer(fixedArrayInitializer),
|
||||
FuncCallNode funcCallExpression => GenerateFuncCall(funcCallExpression),
|
||||
IdentifierNode identifier => GenerateIdentifier(identifier),
|
||||
LiteralNode literal => GenerateLiteral(literal),
|
||||
@@ -660,29 +715,56 @@ public class Generator
|
||||
|
||||
private string GenerateArrayIndex(ArrayIndexAccessNode arrayIndexAccess)
|
||||
{
|
||||
var arrayType = ((NubArrayType)arrayIndexAccess.Array.Type).BaseType;
|
||||
|
||||
var array = GenerateExpression(arrayIndexAccess.Array);
|
||||
var index = GenerateExpression(arrayIndexAccess.Index);
|
||||
|
||||
GenerateArrayBoundsCheck(array, index);
|
||||
|
||||
var firstItemPointerName = GenVarName();
|
||||
_builder.AppendLine($" {firstItemPointerName} =l add {array}, 8");
|
||||
var offsetPointerName = GenVarName();
|
||||
_builder.AppendLine($" {offsetPointerName} =l mul {index}, {QbeTypeSize(arrayType)}");
|
||||
var resultPointerName = GenVarName();
|
||||
_builder.AppendLine($" {resultPointerName} =l add {firstItemPointerName}, {offsetPointerName}");
|
||||
switch (arrayIndexAccess.Array.Type)
|
||||
{
|
||||
case NubArrayType arrayType:
|
||||
{
|
||||
var firstItemPointerName = GenVarName();
|
||||
_builder.AppendLine($" {firstItemPointerName} =l add {array}, 8");
|
||||
var offsetPointerName = GenVarName();
|
||||
_builder.AppendLine($" {offsetPointerName} =l mul {index}, {SizeOf(arrayType.ElementType)}");
|
||||
var resultPointerName = GenVarName();
|
||||
_builder.AppendLine($" {resultPointerName} =l add {firstItemPointerName}, {offsetPointerName}");
|
||||
|
||||
if (IsLargeType(arrayType))
|
||||
{
|
||||
return resultPointerName;
|
||||
}
|
||||
else
|
||||
{
|
||||
var outputName = GenVarName();
|
||||
_builder.AppendLine($" {outputName} {QBEAssign(arrayType)} {QBELoad(arrayType)} {resultPointerName}");
|
||||
return outputName;
|
||||
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:
|
||||
{
|
||||
var firstItemPointerName = GenVarName();
|
||||
_builder.AppendLine($" {firstItemPointerName} =l add {array}, 8");
|
||||
var offsetPointerName = GenVarName();
|
||||
_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;
|
||||
}
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new UnreachableException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -714,7 +796,7 @@ public class Generator
|
||||
{
|
||||
var capacity = GenerateExpression(arrayInitializer.Capacity);
|
||||
var capacityInBytes = GenVarName();
|
||||
_builder.AppendLine($" {capacityInBytes} =l mul {capacity}, {QbeTypeSize(arrayInitializer.ElementType)}");
|
||||
_builder.AppendLine($" {capacityInBytes} =l mul {capacity}, {SizeOf(arrayInitializer.ElementType)}");
|
||||
var totalArraySize = GenVarName();
|
||||
_builder.AppendLine($" {totalArraySize} =l add {capacityInBytes}, 8");
|
||||
var outputName = GenVarName();
|
||||
@@ -1483,7 +1565,7 @@ public class Generator
|
||||
var structDefinition = LookupStructDefinition(structInitializer.StructType.Namespace, structInitializer.StructType.Name);
|
||||
|
||||
var structVar = GenVarName();
|
||||
var size = structDefinition.Fields.Sum(x => QbeTypeSize(x.Type));
|
||||
var size = structDefinition.Fields.Sum(x => SizeOf(x.Type));
|
||||
_builder.AppendLine($" {structVar} =l alloc8 {size}");
|
||||
|
||||
foreach (var field in structDefinition.Fields)
|
||||
@@ -1498,7 +1580,7 @@ public class Generator
|
||||
|
||||
if (IsLargeType(field.Type))
|
||||
{
|
||||
_builder.AppendLine($" blit {var}, {offsetName}, {QbeTypeSize(field.Type)}");
|
||||
_builder.AppendLine($" blit {var}, {offsetName}, {SizeOf(field.Type)}");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1513,7 +1595,7 @@ public class Generator
|
||||
|
||||
if (IsLargeType(field.Type))
|
||||
{
|
||||
_builder.AppendLine($" blit {var}, {offsetName}, {QbeTypeSize(field.Type)}");
|
||||
_builder.AppendLine($" blit {var}, {offsetName}, {SizeOf(field.Type)}");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1620,6 +1702,20 @@ public class Generator
|
||||
}
|
||||
}
|
||||
|
||||
private string GenerateFixedArrayInitializer(FixedArrayInitializerNode fixedArrayInitializer)
|
||||
{
|
||||
var capacityInBytes = SizeOf(fixedArrayInitializer.Type);
|
||||
var outputName = GenVarName();
|
||||
_builder.AppendLine($" {outputName} =l alloc8 {capacityInBytes + 8}");
|
||||
_builder.AppendLine($" storel {fixedArrayInitializer.Capacity}, {outputName}");
|
||||
|
||||
var dataPtr = GenVarName();
|
||||
_builder.AppendLine($" {dataPtr} =l add {outputName}, 8");
|
||||
_builder.AppendLine($" call $nub_memset(l {dataPtr}, w 0, l {capacityInBytes})");
|
||||
|
||||
return outputName;
|
||||
}
|
||||
|
||||
private string GenerateFuncCall(FuncCallNode funcCall)
|
||||
{
|
||||
var funcDefinition = LookupFuncSignature(funcCall.Namespace, funcCall.Name, funcCall.Parameters.Select(p => p.Type).ToList());
|
||||
@@ -1664,11 +1760,6 @@ public class Generator
|
||||
return $"%v{++_variableIndex}";
|
||||
}
|
||||
|
||||
private string GenFuncName()
|
||||
{
|
||||
return $"$f{++_funcIndex}";
|
||||
}
|
||||
|
||||
private string GenLabelName()
|
||||
{
|
||||
return $"@l{++_labelIndex}";
|
||||
@@ -1694,7 +1785,7 @@ public class Generator
|
||||
|
||||
private int LookupMemberOffset(StructDefinitionNode structDefinition, string member)
|
||||
{
|
||||
return structDefinition.Fields.TakeWhile(f => f.Name != member).Sum(f => QbeTypeSize(f.Type));
|
||||
return structDefinition.Fields.TakeWhile(f => f.Name != member).Sum(f => SizeOf(f.Type));
|
||||
}
|
||||
|
||||
private class Variable
|
||||
|
||||
@@ -18,6 +18,7 @@ public class Lexer
|
||||
["alloc"] = Symbol.Alloc,
|
||||
["struct"] = Symbol.Struct,
|
||||
["let"] = Symbol.Let,
|
||||
["calls"] = Symbol.Calls,
|
||||
};
|
||||
|
||||
private static readonly Dictionary<string, Modifier> Modifiers = new()
|
||||
|
||||
@@ -42,5 +42,6 @@ public enum Symbol
|
||||
DoubleColon,
|
||||
Namespace,
|
||||
Let,
|
||||
Alloc
|
||||
Alloc,
|
||||
Calls
|
||||
}
|
||||
@@ -16,6 +16,7 @@ public class FuncParameter(string name, NubType type, bool variadic)
|
||||
public interface IFuncSignature
|
||||
{
|
||||
public string Name { get; }
|
||||
public string Namespace { get; }
|
||||
public List<FuncParameter> Parameters { get; }
|
||||
public Optional<NubType> ReturnType { get; }
|
||||
|
||||
@@ -53,9 +54,10 @@ public interface IFuncSignature
|
||||
public string ToString() => $"{Name}({string.Join(", ", Parameters.Select(p => p.ToString()))}){(ReturnType.HasValue ? ": " + ReturnType.Value : "")}";
|
||||
}
|
||||
|
||||
public class LocalFuncDefinitionNode(IReadOnlyList<Token> tokens, Optional<string> documentation, string name, List<FuncParameter> parameters, BlockNode body, Optional<NubType> returnType, bool exported) : DefinitionNode(tokens, documentation), IFuncSignature
|
||||
public class LocalFuncDefinitionNode(IReadOnlyList<Token> tokens, Optional<string> documentation, string name, string @namespace, List<FuncParameter> parameters, BlockNode body, Optional<NubType> returnType, bool exported) : DefinitionNode(tokens, documentation), IFuncSignature
|
||||
{
|
||||
public string Name { get; } = name;
|
||||
public string Namespace { get; } = @namespace;
|
||||
public List<FuncParameter> Parameters { get; } = parameters;
|
||||
public BlockNode Body { get; } = body;
|
||||
public Optional<NubType> ReturnType { get; } = returnType;
|
||||
@@ -64,9 +66,11 @@ public class LocalFuncDefinitionNode(IReadOnlyList<Token> tokens, Optional<strin
|
||||
public override string ToString() => $"{Name}({string.Join(", ", Parameters.Select(p => p.ToString()))}){(ReturnType.HasValue ? ": " + ReturnType.Value : "")}";
|
||||
}
|
||||
|
||||
public class ExternFuncDefinitionNode(IReadOnlyList<Token> tokens, Optional<string> documentation, string name, List<FuncParameter> parameters, Optional<NubType> returnType) : DefinitionNode(tokens, documentation), IFuncSignature
|
||||
public class ExternFuncDefinitionNode(IReadOnlyList<Token> tokens, Optional<string> documentation, string name, string @namespace, string callName, List<FuncParameter> parameters, Optional<NubType> returnType) : DefinitionNode(tokens, documentation), IFuncSignature
|
||||
{
|
||||
public string Name { get; } = name;
|
||||
public string Namespace { get; } = @namespace;
|
||||
public string CallName { get; } = callName;
|
||||
public List<FuncParameter> Parameters { get; } = parameters;
|
||||
public Optional<NubType> ReturnType { get; } = returnType;
|
||||
|
||||
|
||||
@@ -11,8 +11,9 @@ public class StructField(string name, NubType type, Optional<ExpressionNode> val
|
||||
public Optional<ExpressionNode> Value { get; } = value;
|
||||
}
|
||||
|
||||
public class StructDefinitionNode(IReadOnlyList<Token> tokens, Optional<string> documentation, string name, List<StructField> fields) : DefinitionNode(tokens, documentation)
|
||||
public class StructDefinitionNode(IReadOnlyList<Token> tokens, Optional<string> documentation, string name, string @namespace, List<StructField> fields) : DefinitionNode(tokens, documentation)
|
||||
{
|
||||
public string Name { get; } = name;
|
||||
public string Namespace { get; } = @namespace;
|
||||
public List<StructField> Fields { get; } = fields;
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Nub.Lang.Diagnostics;
|
||||
using Nub.Lang.Frontend.Lexing;
|
||||
using Nub.Lang.Frontend.Parsing.Definitions;
|
||||
@@ -116,7 +117,14 @@ public class Parser
|
||||
.Build());
|
||||
}
|
||||
|
||||
return new ExternFuncDefinitionNode(GetTokensForNode(startIndex), documentation, name.Value, parameters, returnType);
|
||||
var callName = name.Value;
|
||||
|
||||
if (TryExpectSymbol(Symbol.Calls))
|
||||
{
|
||||
callName = ExpectIdentifier().Value;
|
||||
}
|
||||
|
||||
return new ExternFuncDefinitionNode(GetTokensForNode(startIndex), documentation, name.Value, _namespace, callName, parameters, returnType);
|
||||
}
|
||||
|
||||
var body = ParseBlock();
|
||||
@@ -131,7 +139,7 @@ public class Parser
|
||||
.Build());
|
||||
}
|
||||
|
||||
return new LocalFuncDefinitionNode(GetTokensForNode(startIndex), documentation, name.Value, parameters, body, returnType, exported);
|
||||
return new LocalFuncDefinitionNode(GetTokensForNode(startIndex), documentation, name.Value, _namespace, parameters, body, returnType, exported);
|
||||
}
|
||||
|
||||
private StructDefinitionNode ParseStruct(int startIndex, List<ModifierToken> _, Optional<string> documentation)
|
||||
@@ -158,7 +166,7 @@ public class Parser
|
||||
variables.Add(new StructField(variableName, variableType, variableValue));
|
||||
}
|
||||
|
||||
return new StructDefinitionNode(GetTokensForNode(startIndex), documentation, name, variables);
|
||||
return new StructDefinitionNode(GetTokensForNode(startIndex), documentation, name, _namespace, variables);
|
||||
}
|
||||
|
||||
private FuncParameter ParseFuncParameter()
|
||||
@@ -521,11 +529,35 @@ public class Parser
|
||||
}
|
||||
case Symbol.OpenBracket:
|
||||
{
|
||||
var capacity = ParseExpression();
|
||||
ExpectSymbol(Symbol.CloseBracket);
|
||||
var type = ParseType();
|
||||
if (Peek().TryGetValue(out var capacityToken) && capacityToken is LiteralToken { Type: NubPrimitiveType { Kind: PrimitiveTypeKind.I64 } } literalToken)
|
||||
{
|
||||
var capacity = int.Parse(literalToken.Value);
|
||||
Next();
|
||||
ExpectSymbol(Symbol.CloseBracket);
|
||||
var elementType = ParseType();
|
||||
|
||||
if (capacity > 0)
|
||||
{
|
||||
expr = new FixedArrayInitializerNode(GetTokensForNode(startIndex), elementType, capacity);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ParseException(Diagnostic
|
||||
.Error("Fixed array size must be a positive integer")
|
||||
.WithHelp("Use a positive integer literal for the array size")
|
||||
.At(literalToken)
|
||||
.Build());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var capacity = ParseExpression();
|
||||
ExpectSymbol(Symbol.CloseBracket);
|
||||
var type = ParseType();
|
||||
|
||||
expr = new ArrayInitializerNode(GetTokensForNode(startIndex), capacity, type);
|
||||
expr = new ArrayInitializerNode(GetTokensForNode(startIndex), capacity, type);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case Symbol.Alloc:
|
||||
@@ -657,12 +689,32 @@ public class Parser
|
||||
|
||||
if (TryExpectSymbol(Symbol.OpenBracket))
|
||||
{
|
||||
ExpectSymbol(Symbol.CloseBracket);
|
||||
var baseType = ParseType();
|
||||
return new NubArrayType(baseType);
|
||||
if (Peek().TryGetValue(out var token) && token is LiteralToken { Type: NubPrimitiveType { Kind: PrimitiveTypeKind.I64 }, Value: var sizeValue })
|
||||
{
|
||||
Next();
|
||||
ExpectSymbol(Symbol.CloseBracket);
|
||||
var baseType = ParseType();
|
||||
|
||||
var size = int.Parse(sizeValue);
|
||||
|
||||
if (size > 0)
|
||||
{
|
||||
return new NubFixedArrayType(baseType, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new UnreachableException();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ExpectSymbol(Symbol.CloseBracket);
|
||||
var baseType = ParseType();
|
||||
return new NubArrayType(baseType);
|
||||
}
|
||||
}
|
||||
|
||||
if (!Peek().TryGetValue(out var token))
|
||||
if (!Peek().TryGetValue(out var peekToken))
|
||||
{
|
||||
throw new ParseException(Diagnostic
|
||||
.Error("Unexpected end of file while parsing type")
|
||||
@@ -674,9 +726,9 @@ public class Parser
|
||||
throw new ParseException(Diagnostic
|
||||
.Error("Invalid type syntax")
|
||||
.WithHelp("Expected type name, '^' for pointer, or '[]' for array")
|
||||
.At(token)
|
||||
.At(peekToken)
|
||||
.Build());
|
||||
}
|
||||
}
|
||||
|
||||
private Token ExpectToken()
|
||||
{
|
||||
@@ -803,9 +855,9 @@ public class Parser
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<Token> Peek()
|
||||
private Optional<Token> Peek(int offset = 0)
|
||||
{
|
||||
var peekIndex = _index;
|
||||
var peekIndex = _index + offset;
|
||||
while (peekIndex < _tokens.Count && _tokens[peekIndex] is DocumentationToken)
|
||||
{
|
||||
peekIndex++;
|
||||
|
||||
@@ -6,7 +6,22 @@ public abstract class NubType
|
||||
{
|
||||
public static bool IsCompatibleWith(NubType sourceType, NubType targetType)
|
||||
{
|
||||
return targetType.Equals(NubPrimitiveType.Any) || sourceType.Equals(targetType);
|
||||
if (targetType.Equals(NubPrimitiveType.Any) || sourceType.Equals(targetType))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (sourceType is NubFixedArrayType fixedArray && targetType is NubArrayType array && IsCompatibleWith(fixedArray.ElementType, array.ElementType))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (sourceType.Equals(NubPrimitiveType.String) && targetType is NubArrayType arrayType && IsCompatibleWith(NubPrimitiveType.U8, arrayType.ElementType))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public abstract override bool Equals(object? obj);
|
||||
@@ -55,27 +70,45 @@ public class NubPointerType(NubType baseType) : NubType
|
||||
}
|
||||
}
|
||||
|
||||
public class NubArrayType(NubType baseType) : NubType
|
||||
public class NubArrayType(NubType elementType) : NubType
|
||||
{
|
||||
public NubType BaseType { get; } = baseType;
|
||||
public NubType ElementType { get; } = elementType;
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (obj is NubArrayType other)
|
||||
{
|
||||
return BaseType.Equals(other.BaseType);
|
||||
return ElementType.Equals(other.ElementType);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(BaseType);
|
||||
return HashCode.Combine(ElementType);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "[]" + BaseType;
|
||||
return "[]" + ElementType;
|
||||
}
|
||||
}
|
||||
|
||||
public class NubFixedArrayType(NubType elementType, int capacity) : NubType
|
||||
{
|
||||
public NubType ElementType { get; } = elementType;
|
||||
public int Capacity { get; } = capacity;
|
||||
|
||||
public override string ToString() => $"[{Capacity}]{ElementType}";
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is NubFixedArrayType other && ElementType.Equals(other.ElementType) && Capacity == other.Capacity;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(ElementType, Capacity);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Diagnostics;
|
||||
using Nub.Lang.Diagnostics;
|
||||
using Nub.Lang.Frontend.Parsing;
|
||||
using Nub.Lang.Frontend.Parsing.Definitions;
|
||||
@@ -245,6 +246,11 @@ public class TypeChecker
|
||||
return nubPointerType.BaseType;
|
||||
}
|
||||
|
||||
private NubType TypeCheckFixedInitializerArray(FixedArrayInitializerNode fixedArrayInitializer)
|
||||
{
|
||||
return new NubFixedArrayType(fixedArrayInitializer.ElementType, fixedArrayInitializer.Capacity);
|
||||
}
|
||||
|
||||
private NubType? TypeCheckFuncCall(FuncCallNode funcCall, Node node)
|
||||
{
|
||||
List<NubType> parameterTypes = [];
|
||||
@@ -375,11 +381,12 @@ public class TypeChecker
|
||||
BinaryExpressionNode binaryExpr => TypeCheckBinaryExpression(binaryExpr),
|
||||
CastNode cast => TypeCheckCast(cast),
|
||||
DereferenceNode dereference => TypeCheckDereference(dereference),
|
||||
FixedArrayInitializerNode fixedArray => TypeCheckFixedInitializerArray(fixedArray),
|
||||
FuncCallNode funcCallExpr => TypeCheckFuncCall(funcCallExpr, funcCallExpr),
|
||||
StructInitializerNode structInit => TypeCheckStructInitializer(structInit),
|
||||
UnaryExpressionNode unaryExpression => TypeCheckUnaryExpression(unaryExpression),
|
||||
MemberAccessNode memberAccess => TypeCheckMemberAccess(memberAccess),
|
||||
_ => ReportUnsupportedExpression(expression)
|
||||
_ => throw new UnreachableException()
|
||||
};
|
||||
|
||||
if (resultType != null)
|
||||
@@ -390,30 +397,28 @@ public class TypeChecker
|
||||
return resultType;
|
||||
}
|
||||
|
||||
private NubType? ReportUnsupportedExpression(ExpressionNode expression)
|
||||
{
|
||||
ReportError($"Unsupported expression type: {expression.GetType().Name}", expression);
|
||||
return null;
|
||||
}
|
||||
|
||||
private NubType? TypeCheckArrayIndex(ArrayIndexAccessNode arrayIndexAccess)
|
||||
{
|
||||
var expressionType = TypeCheckExpression(arrayIndexAccess.Array);
|
||||
if (expressionType == null) return null;
|
||||
|
||||
if (expressionType is not NubArrayType arrayType)
|
||||
{
|
||||
ReportError($"Cannot access index of non-array type {expressionType}", arrayIndexAccess.Array);
|
||||
return null;
|
||||
}
|
||||
|
||||
var indexType = TypeCheckExpression(arrayIndexAccess.Index);
|
||||
if (indexType != null && !IsInteger(indexType))
|
||||
{
|
||||
ReportError("Array index type must be an integer", arrayIndexAccess.Index);
|
||||
}
|
||||
|
||||
if (expressionType is NubArrayType arrayType)
|
||||
{
|
||||
return arrayType.ElementType;
|
||||
}
|
||||
|
||||
if (expressionType is NubFixedArrayType fixedArrayType)
|
||||
{
|
||||
return fixedArrayType.ElementType;
|
||||
}
|
||||
|
||||
return arrayType.BaseType;
|
||||
ReportError($"Cannot access index of non-array type {expressionType}", arrayIndexAccess.Array);
|
||||
return null;
|
||||
}
|
||||
|
||||
private NubType TypeCheckArrayInitializer(ArrayInitializerNode arrayInitializer)
|
||||
|
||||
Reference in New Issue
Block a user