...
This commit is contained in:
@@ -3,6 +3,6 @@ import c
|
|||||||
global func main(argc: i64, argv: i64) {
|
global func main(argc: i64, argv: i64) {
|
||||||
printf("args: %d, starts at %p\n", argc, argv)
|
printf("args: %d, starts at %p\n", argc, argv)
|
||||||
|
|
||||||
x: i8 = (i8)320000
|
|
||||||
printf("%d\n", x)
|
printf("%s\n", list.text)
|
||||||
}
|
}
|
||||||
@@ -8,11 +8,11 @@ public class Generator
|
|||||||
{
|
{
|
||||||
private readonly List<DefinitionNode> _definitions;
|
private readonly List<DefinitionNode> _definitions;
|
||||||
private readonly StringBuilder _builder = new();
|
private readonly StringBuilder _builder = new();
|
||||||
private readonly Dictionary<string, int> _prefixIndexes = new();
|
|
||||||
private readonly Dictionary<string, Variable> _variables = new();
|
private readonly Dictionary<string, Variable> _variables = new();
|
||||||
private readonly List<string> _strings = [];
|
private readonly List<string> _strings = [];
|
||||||
private readonly Stack<string> _breakLabels = new();
|
private readonly Stack<string> _breakLabels = new();
|
||||||
private readonly Stack<string> _continueLabels = new();
|
private readonly Stack<string> _continueLabels = new();
|
||||||
|
private int _variableIndex;
|
||||||
private bool _codeIsReachable = true;
|
private bool _codeIsReachable = true;
|
||||||
|
|
||||||
public Generator(List<DefinitionNode> definitions)
|
public Generator(List<DefinitionNode> definitions)
|
||||||
@@ -72,7 +72,7 @@ public class Generator
|
|||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case NubCustomType nubCustomType:
|
case NubStructType:
|
||||||
{
|
{
|
||||||
return "l";
|
return "l";
|
||||||
}
|
}
|
||||||
@@ -114,7 +114,7 @@ public class Generator
|
|||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case NubCustomType nubCustomType:
|
case NubStructType nubCustomType:
|
||||||
{
|
{
|
||||||
return ":" + nubCustomType.Name;
|
return ":" + nubCustomType.Name;
|
||||||
}
|
}
|
||||||
@@ -159,7 +159,7 @@ public class Generator
|
|||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case NubCustomType nubCustomType:
|
case NubStructType nubCustomType:
|
||||||
{
|
{
|
||||||
return ":" + nubCustomType.Name;
|
return ":" + nubCustomType.Name;
|
||||||
}
|
}
|
||||||
@@ -170,7 +170,7 @@ public class Generator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int QbeTypeSize(NubType type)
|
private int QbeTypeSize(NubType type)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
@@ -201,9 +201,14 @@ public class Generator
|
|||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case NubCustomType nubCustomType:
|
case NubStructType nubCustomType:
|
||||||
{
|
{
|
||||||
return 8;
|
var definition = _definitions.OfType<StructDefinitionNode>().FirstOrDefault(s => s.Name == nubCustomType.Name);
|
||||||
|
if (definition == null)
|
||||||
|
{
|
||||||
|
throw new Exception($"Cannot determine size of non-existent type {nubCustomType}");
|
||||||
|
}
|
||||||
|
return definition.Fields.Sum(f => QbeTypeSize(f.Type));
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -246,19 +251,19 @@ public class Generator
|
|||||||
switch (FQT(parameter.Type))
|
switch (FQT(parameter.Type))
|
||||||
{
|
{
|
||||||
case "sb":
|
case "sb":
|
||||||
parameterName = GenName("c");
|
parameterName = GenName();
|
||||||
_builder.AppendLine($" %{parameterName} =w extsb %{parameter.Name}");
|
_builder.AppendLine($" %{parameterName} =w extsb %{parameter.Name}");
|
||||||
break;
|
break;
|
||||||
case "ub":
|
case "ub":
|
||||||
parameterName = GenName("c");
|
parameterName = GenName();
|
||||||
_builder.AppendLine($" %{parameterName} =w extub %{parameter.Name}");
|
_builder.AppendLine($" %{parameterName} =w extub %{parameter.Name}");
|
||||||
break;
|
break;
|
||||||
case "sh":
|
case "sh":
|
||||||
parameterName = GenName("c");
|
parameterName = GenName();
|
||||||
_builder.AppendLine($" %{parameterName} =w extsh %{parameter.Name}");
|
_builder.AppendLine($" %{parameterName} =w extsh %{parameter.Name}");
|
||||||
break;
|
break;
|
||||||
case "uh":
|
case "uh":
|
||||||
parameterName = GenName("c");
|
parameterName = GenName();
|
||||||
_builder.AppendLine($" %{parameterName} =w extuh %{parameter.Name}");
|
_builder.AppendLine($" %{parameterName} =w extuh %{parameter.Name}");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -403,9 +408,9 @@ public class Generator
|
|||||||
|
|
||||||
private void GenerateIf(IfNode ifStatement)
|
private void GenerateIf(IfNode ifStatement)
|
||||||
{
|
{
|
||||||
var trueLabel = GenName("true");
|
var trueLabel = GenName();
|
||||||
var falseLabel = GenName("false");
|
var falseLabel = GenName();
|
||||||
var endLabel = GenName("endif");
|
var endLabel = GenName();
|
||||||
|
|
||||||
var result = GenerateExpression(ifStatement.Condition);
|
var result = GenerateExpression(ifStatement.Condition);
|
||||||
_builder.AppendLine($" jnz {result}, @{trueLabel}, @{falseLabel}");
|
_builder.AppendLine($" jnz {result}, @{trueLabel}, @{falseLabel}");
|
||||||
@@ -450,9 +455,9 @@ public class Generator
|
|||||||
|
|
||||||
private void GenerateWhile(WhileNode whileStatement)
|
private void GenerateWhile(WhileNode whileStatement)
|
||||||
{
|
{
|
||||||
var conditionLabel = GenName("condition");
|
var conditionLabel = GenName();
|
||||||
var iterationLabel = GenName("iteration");
|
var iterationLabel = GenName();
|
||||||
var endLabel = GenName("endloop");
|
var endLabel = GenName();
|
||||||
|
|
||||||
_breakLabels.Push(endLabel);
|
_breakLabels.Push(endLabel);
|
||||||
_continueLabels.Push(conditionLabel);
|
_continueLabels.Push(conditionLabel);
|
||||||
@@ -734,7 +739,7 @@ public class Generator
|
|||||||
throw new NotSupportedException("Casting is only supported for primitive types");
|
throw new NotSupportedException("Casting is only supported for primitive types");
|
||||||
}
|
}
|
||||||
|
|
||||||
var outputLabel = GenName("c");
|
var outputLabel = GenName();
|
||||||
|
|
||||||
switch (primitiveInputType.Kind)
|
switch (primitiveInputType.Kind)
|
||||||
{
|
{
|
||||||
@@ -779,7 +784,7 @@ public class Generator
|
|||||||
case PrimitiveTypeKind.U8:
|
case PrimitiveTypeKind.U8:
|
||||||
return input;
|
return input;
|
||||||
case PrimitiveTypeKind.F64:
|
case PrimitiveTypeKind.F64:
|
||||||
var extLabel = GenName("ext");
|
var extLabel = GenName();
|
||||||
_builder.AppendLine($" %{extLabel} =l extsw {input}");
|
_builder.AppendLine($" %{extLabel} =l extsw {input}");
|
||||||
_builder.AppendLine($" %{outputLabel} =d sltof %{extLabel}");
|
_builder.AppendLine($" %{outputLabel} =d sltof %{extLabel}");
|
||||||
return $"%{outputLabel}";
|
return $"%{outputLabel}";
|
||||||
@@ -790,7 +795,7 @@ public class Generator
|
|||||||
_builder.AppendLine($" %{outputLabel} =l call $nub_i32_to_string(w {input})");
|
_builder.AppendLine($" %{outputLabel} =l call $nub_i32_to_string(w {input})");
|
||||||
return $"%{outputLabel}";
|
return $"%{outputLabel}";
|
||||||
case PrimitiveTypeKind.Any:
|
case PrimitiveTypeKind.Any:
|
||||||
var extAnyLabel = GenName("ext");
|
var extAnyLabel = GenName();
|
||||||
_builder.AppendLine($" %{extAnyLabel} =l extsw {input}");
|
_builder.AppendLine($" %{extAnyLabel} =l extsw {input}");
|
||||||
return $"%{extAnyLabel}";
|
return $"%{extAnyLabel}";
|
||||||
case PrimitiveTypeKind.Bool:
|
case PrimitiveTypeKind.Bool:
|
||||||
@@ -815,28 +820,28 @@ public class Generator
|
|||||||
return input;
|
return input;
|
||||||
case PrimitiveTypeKind.F64:
|
case PrimitiveTypeKind.F64:
|
||||||
{
|
{
|
||||||
var extLabel = GenName("ext");
|
var extLabel = GenName();
|
||||||
_builder.AppendLine($" %{extLabel} =l extsh {input}");
|
_builder.AppendLine($" %{extLabel} =l extsh {input}");
|
||||||
_builder.AppendLine($" %{outputLabel} =d sltof %{extLabel}");
|
_builder.AppendLine($" %{outputLabel} =d sltof %{extLabel}");
|
||||||
return $"%{outputLabel}";
|
return $"%{outputLabel}";
|
||||||
}
|
}
|
||||||
case PrimitiveTypeKind.F32:
|
case PrimitiveTypeKind.F32:
|
||||||
{
|
{
|
||||||
var extLabel = GenName("ext");
|
var extLabel = GenName();
|
||||||
_builder.AppendLine($" %{extLabel} =w extsh {input}");
|
_builder.AppendLine($" %{extLabel} =w extsh {input}");
|
||||||
_builder.AppendLine($" %{outputLabel} =s swtof %{extLabel}");
|
_builder.AppendLine($" %{outputLabel} =s swtof %{extLabel}");
|
||||||
return $"%{outputLabel}";
|
return $"%{outputLabel}";
|
||||||
}
|
}
|
||||||
case PrimitiveTypeKind.String:
|
case PrimitiveTypeKind.String:
|
||||||
{
|
{
|
||||||
var extLabel = GenName("ext");
|
var extLabel = GenName();
|
||||||
_builder.AppendLine($" %{extLabel} =w extsh {input}");
|
_builder.AppendLine($" %{extLabel} =w extsh {input}");
|
||||||
_builder.AppendLine($" %{outputLabel} =l call $nub_i32_to_string(w %{extLabel})");
|
_builder.AppendLine($" %{outputLabel} =l call $nub_i32_to_string(w %{extLabel})");
|
||||||
return $"%{outputLabel}";
|
return $"%{outputLabel}";
|
||||||
}
|
}
|
||||||
case PrimitiveTypeKind.Any:
|
case PrimitiveTypeKind.Any:
|
||||||
{
|
{
|
||||||
var extLabel = GenName("ext");
|
var extLabel = GenName();
|
||||||
_builder.AppendLine($" %{extLabel} =l extsh {input}");
|
_builder.AppendLine($" %{extLabel} =l extsh {input}");
|
||||||
return $"%{extLabel}";
|
return $"%{extLabel}";
|
||||||
}
|
}
|
||||||
@@ -862,28 +867,28 @@ public class Generator
|
|||||||
return input;
|
return input;
|
||||||
case PrimitiveTypeKind.F64:
|
case PrimitiveTypeKind.F64:
|
||||||
{
|
{
|
||||||
var extLabel = GenName("ext");
|
var extLabel = GenName();
|
||||||
_builder.AppendLine($" %{extLabel} =l extsb {input}");
|
_builder.AppendLine($" %{extLabel} =l extsb {input}");
|
||||||
_builder.AppendLine($" %{outputLabel} =d sltof %{extLabel}");
|
_builder.AppendLine($" %{outputLabel} =d sltof %{extLabel}");
|
||||||
return $"%{outputLabel}";
|
return $"%{outputLabel}";
|
||||||
}
|
}
|
||||||
case PrimitiveTypeKind.F32:
|
case PrimitiveTypeKind.F32:
|
||||||
{
|
{
|
||||||
var extLabel = GenName("ext");
|
var extLabel = GenName();
|
||||||
_builder.AppendLine($" %{extLabel} =w extsb {input}");
|
_builder.AppendLine($" %{extLabel} =w extsb {input}");
|
||||||
_builder.AppendLine($" %{outputLabel} =s swtof %{extLabel}");
|
_builder.AppendLine($" %{outputLabel} =s swtof %{extLabel}");
|
||||||
return $"%{outputLabel}";
|
return $"%{outputLabel}";
|
||||||
}
|
}
|
||||||
case PrimitiveTypeKind.String:
|
case PrimitiveTypeKind.String:
|
||||||
{
|
{
|
||||||
var extLabel = GenName("ext");
|
var extLabel = GenName();
|
||||||
_builder.AppendLine($" %{extLabel} =w extsb {input}");
|
_builder.AppendLine($" %{extLabel} =w extsb {input}");
|
||||||
_builder.AppendLine($" %{outputLabel} =l call $nub_i32_to_string(w %{extLabel})");
|
_builder.AppendLine($" %{outputLabel} =l call $nub_i32_to_string(w %{extLabel})");
|
||||||
return $"%{outputLabel}";
|
return $"%{outputLabel}";
|
||||||
}
|
}
|
||||||
case PrimitiveTypeKind.Any:
|
case PrimitiveTypeKind.Any:
|
||||||
{
|
{
|
||||||
var extLabel = GenName("ext");
|
var extLabel = GenName();
|
||||||
_builder.AppendLine($" %{extLabel} =l extsb {input}");
|
_builder.AppendLine($" %{extLabel} =l extsb {input}");
|
||||||
return $"%{extLabel}";
|
return $"%{extLabel}";
|
||||||
}
|
}
|
||||||
@@ -933,7 +938,7 @@ public class Generator
|
|||||||
case PrimitiveTypeKind.U8:
|
case PrimitiveTypeKind.U8:
|
||||||
return input;
|
return input;
|
||||||
case PrimitiveTypeKind.F64:
|
case PrimitiveTypeKind.F64:
|
||||||
var extLabel = GenName("ext");
|
var extLabel = GenName();
|
||||||
_builder.AppendLine($" %{extLabel} =l extuw {input}");
|
_builder.AppendLine($" %{extLabel} =l extuw {input}");
|
||||||
_builder.AppendLine($" %{outputLabel} =d ultof %{extLabel}");
|
_builder.AppendLine($" %{outputLabel} =d ultof %{extLabel}");
|
||||||
return $"%{outputLabel}";
|
return $"%{outputLabel}";
|
||||||
@@ -944,7 +949,7 @@ public class Generator
|
|||||||
_builder.AppendLine($" %{outputLabel} =l call $nub_u32_to_string(w {input})");
|
_builder.AppendLine($" %{outputLabel} =l call $nub_u32_to_string(w {input})");
|
||||||
return $"%{outputLabel}";
|
return $"%{outputLabel}";
|
||||||
case PrimitiveTypeKind.Any:
|
case PrimitiveTypeKind.Any:
|
||||||
var extAnyLabel = GenName("ext");
|
var extAnyLabel = GenName();
|
||||||
_builder.AppendLine($" %{extAnyLabel} =l extuw {input}");
|
_builder.AppendLine($" %{extAnyLabel} =l extuw {input}");
|
||||||
return $"%{extAnyLabel}";
|
return $"%{extAnyLabel}";
|
||||||
case PrimitiveTypeKind.Bool:
|
case PrimitiveTypeKind.Bool:
|
||||||
@@ -969,28 +974,28 @@ public class Generator
|
|||||||
return input;
|
return input;
|
||||||
case PrimitiveTypeKind.F64:
|
case PrimitiveTypeKind.F64:
|
||||||
{
|
{
|
||||||
var extLabel = GenName("ext");
|
var extLabel = GenName();
|
||||||
_builder.AppendLine($" %{extLabel} =l extuh {input}");
|
_builder.AppendLine($" %{extLabel} =l extuh {input}");
|
||||||
_builder.AppendLine($" %{outputLabel} =d ultof %{extLabel}");
|
_builder.AppendLine($" %{outputLabel} =d ultof %{extLabel}");
|
||||||
return $"%{outputLabel}";
|
return $"%{outputLabel}";
|
||||||
}
|
}
|
||||||
case PrimitiveTypeKind.F32:
|
case PrimitiveTypeKind.F32:
|
||||||
{
|
{
|
||||||
var extLabel = GenName("ext");
|
var extLabel = GenName();
|
||||||
_builder.AppendLine($" %{extLabel} =w extuh {input}");
|
_builder.AppendLine($" %{extLabel} =w extuh {input}");
|
||||||
_builder.AppendLine($" %{outputLabel} =s uwtof %{extLabel}");
|
_builder.AppendLine($" %{outputLabel} =s uwtof %{extLabel}");
|
||||||
return $"%{outputLabel}";
|
return $"%{outputLabel}";
|
||||||
}
|
}
|
||||||
case PrimitiveTypeKind.String:
|
case PrimitiveTypeKind.String:
|
||||||
{
|
{
|
||||||
var extLabel = GenName("ext");
|
var extLabel = GenName();
|
||||||
_builder.AppendLine($" %{extLabel} =w extuh {input}");
|
_builder.AppendLine($" %{extLabel} =w extuh {input}");
|
||||||
_builder.AppendLine($" %{outputLabel} =l call $nub_u32_to_string(w %{extLabel})");
|
_builder.AppendLine($" %{outputLabel} =l call $nub_u32_to_string(w %{extLabel})");
|
||||||
return $"%{outputLabel}";
|
return $"%{outputLabel}";
|
||||||
}
|
}
|
||||||
case PrimitiveTypeKind.Any:
|
case PrimitiveTypeKind.Any:
|
||||||
{
|
{
|
||||||
var extLabel = GenName("ext");
|
var extLabel = GenName();
|
||||||
_builder.AppendLine($" %{extLabel} =l extuh {input}");
|
_builder.AppendLine($" %{extLabel} =l extuh {input}");
|
||||||
return $"%{extLabel}";
|
return $"%{extLabel}";
|
||||||
}
|
}
|
||||||
@@ -1016,28 +1021,28 @@ public class Generator
|
|||||||
return input;
|
return input;
|
||||||
case PrimitiveTypeKind.F64:
|
case PrimitiveTypeKind.F64:
|
||||||
{
|
{
|
||||||
var extLabel = GenName("ext");
|
var extLabel = GenName();
|
||||||
_builder.AppendLine($" %{extLabel} =l extub {input}");
|
_builder.AppendLine($" %{extLabel} =l extub {input}");
|
||||||
_builder.AppendLine($" %{outputLabel} =d ultof %{extLabel}");
|
_builder.AppendLine($" %{outputLabel} =d ultof %{extLabel}");
|
||||||
return $"%{outputLabel}";
|
return $"%{outputLabel}";
|
||||||
}
|
}
|
||||||
case PrimitiveTypeKind.F32:
|
case PrimitiveTypeKind.F32:
|
||||||
{
|
{
|
||||||
var extLabel = GenName("ext");
|
var extLabel = GenName();
|
||||||
_builder.AppendLine($" %{extLabel} =w extub {input}");
|
_builder.AppendLine($" %{extLabel} =w extub {input}");
|
||||||
_builder.AppendLine($" %{outputLabel} =s uwtof %{extLabel}");
|
_builder.AppendLine($" %{outputLabel} =s uwtof %{extLabel}");
|
||||||
return $"%{outputLabel}";
|
return $"%{outputLabel}";
|
||||||
}
|
}
|
||||||
case PrimitiveTypeKind.String:
|
case PrimitiveTypeKind.String:
|
||||||
{
|
{
|
||||||
var extLabel = GenName("ext");
|
var extLabel = GenName();
|
||||||
_builder.AppendLine($" %{extLabel} =w extub {input}");
|
_builder.AppendLine($" %{extLabel} =w extub {input}");
|
||||||
_builder.AppendLine($" %{outputLabel} =l call $nub_u32_to_string(w %{extLabel})");
|
_builder.AppendLine($" %{outputLabel} =l call $nub_u32_to_string(w %{extLabel})");
|
||||||
return $"%{outputLabel}";
|
return $"%{outputLabel}";
|
||||||
}
|
}
|
||||||
case PrimitiveTypeKind.Any:
|
case PrimitiveTypeKind.Any:
|
||||||
{
|
{
|
||||||
var extLabel = GenName("ext");
|
var extLabel = GenName();
|
||||||
_builder.AppendLine($" %{extLabel} =l extub {input}");
|
_builder.AppendLine($" %{extLabel} =l extub {input}");
|
||||||
return $"%{extLabel}";
|
return $"%{extLabel}";
|
||||||
}
|
}
|
||||||
@@ -1196,15 +1201,13 @@ public class Generator
|
|||||||
|
|
||||||
private string GenerateStructInitializer(StructInitializerNode structInitializer)
|
private string GenerateStructInitializer(StructInitializerNode structInitializer)
|
||||||
{
|
{
|
||||||
var structDefinition = _definitions.OfType<StructDefinitionNode>()
|
var structDefinition = _definitions.OfType<StructDefinitionNode>().FirstOrDefault(s => s.Name == structInitializer.StructType.Name);
|
||||||
.FirstOrDefault(s => s.Name == structInitializer.StructType.Name);
|
|
||||||
|
|
||||||
if (structDefinition == null)
|
if (structDefinition == null)
|
||||||
{
|
{
|
||||||
throw new Exception($"Struct {structInitializer.StructType.Name} is not defined");
|
throw new Exception($"Struct {structInitializer.StructType.Name} is not defined");
|
||||||
}
|
}
|
||||||
|
|
||||||
var structVar = GenName("struct");
|
var structVar = GenName();
|
||||||
|
|
||||||
var size = structDefinition.Fields.Sum(x => QbeTypeSize(x.Type));
|
var size = structDefinition.Fields.Sum(x => QbeTypeSize(x.Type));
|
||||||
_builder.AppendLine($" %{structVar} =l alloc8 {size}");
|
_builder.AppendLine($" %{structVar} =l alloc8 {size}");
|
||||||
@@ -1216,14 +1219,14 @@ 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 var = GenerateExpression(fieldValue);
|
||||||
var offsetLabel = GenName("offset");
|
var offsetLabel = GenName();
|
||||||
_builder.AppendLine($" %{offsetLabel} =l add %{structVar}, {i * QbeTypeSize(field.Type)}");
|
_builder.AppendLine($" %{offsetLabel} =l add %{structVar}, {i * QbeTypeSize(field.Type)}");
|
||||||
_builder.AppendLine($" store{SQT(field.Type)} {var}, %{offsetLabel}");
|
_builder.AppendLine($" store{SQT(field.Type)} {var}, %{offsetLabel}");
|
||||||
}
|
}
|
||||||
else if (field.Value.HasValue)
|
else if (field.Value.HasValue)
|
||||||
{
|
{
|
||||||
var var = GenerateExpression(field.Value.Value);
|
var var = GenerateExpression(field.Value.Value);
|
||||||
var offsetLabel = GenName("offset");
|
var offsetLabel = GenName();
|
||||||
_builder.AppendLine($" %{offsetLabel} =l add %{structVar}, {i * QbeTypeSize(field.Type)}");
|
_builder.AppendLine($" %{offsetLabel} =l add %{structVar}, {i * QbeTypeSize(field.Type)}");
|
||||||
_builder.AppendLine($" store{SQT(field.Type)} {var}, %{offsetLabel}");
|
_builder.AppendLine($" store{SQT(field.Type)} {var}, %{offsetLabel}");
|
||||||
}
|
}
|
||||||
@@ -1265,10 +1268,10 @@ public class Generator
|
|||||||
throw new Exception($"Field {structFieldAccessor.Field} is not defined in struct {structType.Name}");
|
throw new Exception($"Field {structFieldAccessor.Field} is not defined in struct {structType.Name}");
|
||||||
}
|
}
|
||||||
|
|
||||||
var offsetLabel = GenName("offset");
|
var offsetLabel = GenName();
|
||||||
_builder.AppendLine($" %{offsetLabel} =l add {@struct}, {fieldIndex * QbeTypeSize(structFieldAccessor.Type)}");
|
_builder.AppendLine($" %{offsetLabel} =l add {@struct}, {fieldIndex * QbeTypeSize(structFieldAccessor.Type)}");
|
||||||
|
|
||||||
var outputLabel = GenName("field");
|
var outputLabel = GenName();
|
||||||
_builder.AppendLine($" %{outputLabel} ={SQT(structFieldAccessor.Type)} load{SQT(structFieldAccessor.Type)} %{offsetLabel}");
|
_builder.AppendLine($" %{outputLabel} ={SQT(structFieldAccessor.Type)} load{SQT(structFieldAccessor.Type)} %{offsetLabel}");
|
||||||
|
|
||||||
return $"%{outputLabel}";
|
return $"%{outputLabel}";
|
||||||
@@ -1282,11 +1285,9 @@ public class Generator
|
|||||||
return $"%{outputLabel}";
|
return $"%{outputLabel}";
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GenName(string prefix = "v")
|
private string GenName()
|
||||||
{
|
{
|
||||||
var index = _prefixIndexes.GetValueOrDefault(prefix, 0);
|
return $"v{++_variableIndex}";
|
||||||
_prefixIndexes[prefix] = index + 1;
|
|
||||||
return $"{prefix}{index}";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Variable
|
private class Variable
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ public class Lexer
|
|||||||
['*'] = Symbol.Star,
|
['*'] = Symbol.Star,
|
||||||
['/'] = Symbol.ForwardSlash,
|
['/'] = Symbol.ForwardSlash,
|
||||||
['!'] = Symbol.Bang,
|
['!'] = Symbol.Bang,
|
||||||
|
['^'] = Symbol.Caret,
|
||||||
|
['&'] = Symbol.Ampersand,
|
||||||
};
|
};
|
||||||
|
|
||||||
private string _src = string.Empty;
|
private string _src = string.Empty;
|
||||||
|
|||||||
@@ -39,5 +39,7 @@ public enum Symbol
|
|||||||
Star,
|
Star,
|
||||||
ForwardSlash,
|
ForwardSlash,
|
||||||
New,
|
New,
|
||||||
Struct
|
Struct,
|
||||||
|
Caret,
|
||||||
|
Ampersand
|
||||||
}
|
}
|
||||||
@@ -76,6 +76,7 @@ public class Parser
|
|||||||
{
|
{
|
||||||
throw new Exception($"Modifiers: {string.Join(", ", modifiers)} is not valid for an extern function");
|
throw new Exception($"Modifiers: {string.Join(", ", modifiers)} is not valid for an extern function");
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ExternFuncDefinitionNode(name.Value, parameters, returnType);
|
return new ExternFuncDefinitionNode(name.Value, parameters, returnType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,10 +87,11 @@ public class Parser
|
|||||||
{
|
{
|
||||||
throw new Exception($"Modifiers: {string.Join(", ", modifiers)} is not valid for a local function");
|
throw new Exception($"Modifiers: {string.Join(", ", modifiers)} is not valid for a local function");
|
||||||
}
|
}
|
||||||
|
|
||||||
return new LocalFuncDefinitionNode(name.Value, parameters, body, returnType, global);
|
return new LocalFuncDefinitionNode(name.Value, parameters, body, returnType, global);
|
||||||
}
|
}
|
||||||
|
|
||||||
private StructDefinitionNode ParseStruct(List<Modifier> modifiers)
|
private StructDefinitionNode ParseStruct(List<Modifier> _)
|
||||||
{
|
{
|
||||||
var name = ExpectIdentifier().Value;
|
var name = ExpectIdentifier().Value;
|
||||||
|
|
||||||
@@ -324,11 +326,10 @@ public class Parser
|
|||||||
{
|
{
|
||||||
// This is ugly
|
// This is ugly
|
||||||
var nextToken = Peek();
|
var nextToken = Peek();
|
||||||
if (nextToken is { Value: IdentifierToken })
|
if (nextToken is { Value: IdentifierToken or SymbolToken { Symbol: Symbol.Caret } })
|
||||||
{
|
{
|
||||||
var startIndex = _index;
|
var startIndex = _index;
|
||||||
var identifierToken = ExpectIdentifier();
|
var type = ParseType();
|
||||||
var type = NubType.Parse(identifierToken.Value);
|
|
||||||
|
|
||||||
if (TryExpectSymbol(Symbol.CloseParen))
|
if (TryExpectSymbol(Symbol.CloseParen))
|
||||||
{
|
{
|
||||||
@@ -498,17 +499,6 @@ public class Parser
|
|||||||
return identifier;
|
return identifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
private LiteralToken ExpectLiteral()
|
|
||||||
{
|
|
||||||
var token = ExpectToken();
|
|
||||||
if (token is not LiteralToken literal)
|
|
||||||
{
|
|
||||||
throw new Exception($"Expected {nameof(LiteralToken)} but got {token.GetType().Name}");
|
|
||||||
}
|
|
||||||
|
|
||||||
return literal;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Optional<Token> Peek()
|
private Optional<Token> Peek()
|
||||||
{
|
{
|
||||||
while (_index < _tokens.Count && _tokens.ElementAt(_index) is SymbolToken { Symbol: Symbol.Whitespace })
|
while (_index < _tokens.Count && _tokens.ElementAt(_index) is SymbolToken { Symbol: Symbol.Whitespace })
|
||||||
|
|||||||
@@ -10,44 +10,29 @@ public class TypeCheckingException : Exception
|
|||||||
public class TypeChecker
|
public class TypeChecker
|
||||||
{
|
{
|
||||||
private readonly Dictionary<string, NubType> _variables = new();
|
private readonly Dictionary<string, NubType> _variables = new();
|
||||||
private readonly Dictionary<string, (List<FuncParameter> Parameters, Optional<NubType> ReturnType)> _functions = new();
|
private readonly List<DefinitionNode> _definitions;
|
||||||
private readonly Dictionary<string, Dictionary<string, NubType>> _structs = new();
|
|
||||||
private NubType? _currentFunctionReturnType;
|
private NubType? _currentFunctionReturnType;
|
||||||
private bool _hasReturnStatement;
|
private bool _hasReturnStatement;
|
||||||
|
|
||||||
public void TypeCheck(List<DefinitionNode> definitions)
|
public TypeChecker(List<DefinitionNode> definitions)
|
||||||
{
|
{
|
||||||
CollectDefinitions(definitions);
|
_definitions = definitions;
|
||||||
|
|
||||||
foreach (var definition in definitions)
|
|
||||||
{
|
|
||||||
if (definition is LocalFuncDefinitionNode funcDef)
|
|
||||||
{
|
|
||||||
TypeCheckFunction(funcDef);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void TypeCheck()
|
||||||
|
{
|
||||||
|
foreach (var structDef in _definitions.OfType<StructDefinitionNode>())
|
||||||
|
{
|
||||||
|
TypeCheckStructDef(structDef);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var funcDef in _definitions.OfType<LocalFuncDefinitionNode>())
|
||||||
|
{
|
||||||
|
TypeCheckFuncDef(funcDef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CollectDefinitions(List<DefinitionNode> definitions)
|
private void TypeCheckStructDef(StructDefinitionNode structDef)
|
||||||
{
|
|
||||||
foreach (var definition in definitions)
|
|
||||||
{
|
|
||||||
switch (definition)
|
|
||||||
{
|
|
||||||
case StructDefinitionNode structDef:
|
|
||||||
RegisterStruct(structDef);
|
|
||||||
break;
|
|
||||||
case LocalFuncDefinitionNode funcDef:
|
|
||||||
RegisterFunction(funcDef);
|
|
||||||
break;
|
|
||||||
case ExternFuncDefinitionNode externFuncDef:
|
|
||||||
RegisterExternFunction(externFuncDef);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RegisterStruct(StructDefinitionNode structDef)
|
|
||||||
{
|
{
|
||||||
var fields = new Dictionary<string, NubType>();
|
var fields = new Dictionary<string, NubType>();
|
||||||
foreach (var field in structDef.Fields)
|
foreach (var field in structDef.Fields)
|
||||||
@@ -56,22 +41,20 @@ public class TypeChecker
|
|||||||
{
|
{
|
||||||
throw new TypeCheckingException($"Duplicate field '{field.Name}' in struct '{structDef.Name}'");
|
throw new TypeCheckingException($"Duplicate field '{field.Name}' in struct '{structDef.Name}'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (field.Value.HasValue)
|
||||||
|
{
|
||||||
|
if (!TypeCheckExpression(field.Value.Value).Equals(field.Type))
|
||||||
|
{
|
||||||
|
throw new TypeCheckingException("Default field initializer does not match the defined type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fields[field.Name] = field.Type;
|
fields[field.Name] = field.Type;
|
||||||
}
|
}
|
||||||
_structs[structDef.Name] = fields;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RegisterFunction(LocalFuncDefinitionNode funcDef)
|
private void TypeCheckFuncDef(LocalFuncDefinitionNode funcDef)
|
||||||
{
|
|
||||||
_functions[funcDef.Name] = (funcDef.Parameters, funcDef.ReturnType);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RegisterExternFunction(ExternFuncDefinitionNode funcDef)
|
|
||||||
{
|
|
||||||
_functions[funcDef.Name] = (funcDef.Parameters, funcDef.ReturnType);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void TypeCheckFunction(LocalFuncDefinitionNode funcDef)
|
|
||||||
{
|
{
|
||||||
_variables.Clear();
|
_variables.Clear();
|
||||||
_currentFunctionReturnType = funcDef.ReturnType.HasValue ? funcDef.ReturnType.Value : null;
|
_currentFunctionReturnType = funcDef.ReturnType.HasValue ? funcDef.ReturnType.Value : null;
|
||||||
@@ -146,13 +129,28 @@ public class TypeChecker
|
|||||||
|
|
||||||
private NubType TypeCheckFuncCall(FuncCall funcCall)
|
private NubType TypeCheckFuncCall(FuncCall funcCall)
|
||||||
{
|
{
|
||||||
if (!_functions.TryGetValue(funcCall.Name, out var funcSignature))
|
var localFuncDef = _definitions.OfType<LocalFuncDefinitionNode>().FirstOrDefault(f => f.Name == funcCall.Name);
|
||||||
|
var externFuncDef = _definitions.OfType<ExternFuncDefinitionNode>().FirstOrDefault(f => f.Name == funcCall.Name);
|
||||||
|
|
||||||
|
List<FuncParameter> parameters;
|
||||||
|
Optional<NubType> returnType;
|
||||||
|
if (localFuncDef != null)
|
||||||
|
{
|
||||||
|
parameters = localFuncDef.Parameters;
|
||||||
|
returnType = localFuncDef.ReturnType;
|
||||||
|
}
|
||||||
|
else if (externFuncDef != null)
|
||||||
|
{
|
||||||
|
parameters = externFuncDef.Parameters;
|
||||||
|
returnType = externFuncDef.ReturnType;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
{
|
{
|
||||||
throw new TypeCheckingException($"Function '{funcCall.Name}' is not defined");
|
throw new TypeCheckingException($"Function '{funcCall.Name}' is not defined");
|
||||||
}
|
}
|
||||||
|
|
||||||
var paramTypes = funcSignature.Parameters;
|
if (parameters.Take(parameters.Count - 1).Any(x => x.Variadic))
|
||||||
if (paramTypes.Take(paramTypes.Count - 1).Any(x => x.Variadic))
|
|
||||||
{
|
{
|
||||||
throw new TypeCheckingException($"Function '{funcCall.Name}' has multiple variadic parameters");
|
throw new TypeCheckingException($"Function '{funcCall.Name}' has multiple variadic parameters");
|
||||||
}
|
}
|
||||||
@@ -162,13 +160,13 @@ public class TypeChecker
|
|||||||
var argType = TypeCheckExpression(funcCall.Parameters[i]);
|
var argType = TypeCheckExpression(funcCall.Parameters[i]);
|
||||||
|
|
||||||
NubType paramType;
|
NubType paramType;
|
||||||
if (i < paramTypes.Count)
|
if (i < parameters.Count)
|
||||||
{
|
{
|
||||||
paramType = paramTypes[i].Type;
|
paramType = parameters[i].Type;
|
||||||
}
|
}
|
||||||
else if (paramTypes.LastOrDefault()?.Variadic ?? false)
|
else if (parameters.LastOrDefault()?.Variadic ?? false)
|
||||||
{
|
{
|
||||||
return paramTypes[^1].Type;
|
return parameters[^1].Type;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -181,7 +179,7 @@ public class TypeChecker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return funcSignature.ReturnType.HasValue ? funcSignature.ReturnType.Value : NubPrimitiveType.Any;
|
return returnType.HasValue ? returnType.Value : NubPrimitiveType.Any;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TypeCheckIf(IfNode ifNode)
|
private void TypeCheckIf(IfNode ifNode)
|
||||||
@@ -322,36 +320,47 @@ public class TypeChecker
|
|||||||
|
|
||||||
private NubType TypeCheckStructInitializer(StructInitializerNode structInit)
|
private NubType TypeCheckStructInitializer(StructInitializerNode structInit)
|
||||||
{
|
{
|
||||||
|
var initialized = new HashSet<string>();
|
||||||
|
|
||||||
var structType = structInit.StructType;
|
var structType = structInit.StructType;
|
||||||
if (structType is not NubCustomType customType)
|
if (structType is not NubStructType customType)
|
||||||
{
|
{
|
||||||
throw new TypeCheckingException($"Type '{structType}' is not a struct type");
|
throw new TypeCheckingException($"Type '{structType}' is not a struct type");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_structs.TryGetValue(customType.Name, out var fields))
|
var definition = _definitions.OfType<StructDefinitionNode>().FirstOrDefault(s => s.Name == structInit.StructType.Name);
|
||||||
|
if (definition == null)
|
||||||
{
|
{
|
||||||
throw new TypeCheckingException($"Struct type '{customType.Name}' is not defined");
|
throw new TypeCheckingException($"Struct type '{customType.Name}' is not defined");
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var initializer in structInit.Initializers)
|
foreach (var initializer in structInit.Initializers)
|
||||||
{
|
{
|
||||||
if (!fields.TryGetValue(initializer.Key, out var fieldType))
|
var definitionField = definition.Fields.FirstOrDefault(f => f.Name == initializer.Key);
|
||||||
|
if (definitionField == null)
|
||||||
{
|
{
|
||||||
throw new TypeCheckingException($"Field '{initializer.Key}' does not exist in struct '{customType.Name}'");
|
throw new TypeCheckingException($"Field '{initializer.Key}' does not exist in struct '{customType.Name}'");
|
||||||
}
|
}
|
||||||
|
|
||||||
var initializerType = TypeCheckExpression(initializer.Value);
|
var initializerType = TypeCheckExpression(initializer.Value);
|
||||||
if (!AreTypesCompatible(initializerType, fieldType))
|
if (!AreTypesCompatible(initializerType, definitionField.Type))
|
||||||
{
|
{
|
||||||
throw new TypeCheckingException($"Cannot initialize field '{initializer.Key}' of type '{fieldType}' with expression of type '{initializerType}'");
|
throw new TypeCheckingException($"Cannot initialize field '{initializer.Key}' of type '{definitionField.Type}' with expression of type '{initializerType}'");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var field in fields)
|
initialized.Add(initializer.Key);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var field in definition.Fields.Where(f => f.Value.HasValue))
|
||||||
{
|
{
|
||||||
if (!structInit.Initializers.ContainsKey(field.Key))
|
initialized.Add(field.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var field in definition.Fields)
|
||||||
{
|
{
|
||||||
throw new TypeCheckingException($"Field '{field.Key}' of struct '{customType.Name}' is not initialized");
|
if (!initialized.Contains(field.Name))
|
||||||
|
{
|
||||||
|
throw new TypeCheckingException($"Struct field '{field.Name}' is not initialized on type '{customType.Name}'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,23 +370,24 @@ public class TypeChecker
|
|||||||
private NubType TypeCheckStructFieldAccess(StructFieldAccessorNode fieldAccess)
|
private NubType TypeCheckStructFieldAccess(StructFieldAccessorNode fieldAccess)
|
||||||
{
|
{
|
||||||
var structType = TypeCheckExpression(fieldAccess.Struct);
|
var structType = TypeCheckExpression(fieldAccess.Struct);
|
||||||
|
if (structType is not NubStructType customType)
|
||||||
if (structType is not NubCustomType customType)
|
|
||||||
{
|
{
|
||||||
throw new TypeCheckingException($"Cannot access field '{fieldAccess.Field}' on non-struct type '{structType}'");
|
throw new TypeCheckingException($"Cannot access field '{fieldAccess.Field}' on non-struct type '{structType}'");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_structs.TryGetValue(customType.Name, out var fields))
|
var definition = _definitions.OfType<StructDefinitionNode>().FirstOrDefault(s => s.Name == customType.Name);
|
||||||
|
if (definition == null)
|
||||||
{
|
{
|
||||||
throw new TypeCheckingException($"Struct type '{customType.Name}' is not defined");
|
throw new TypeCheckingException($"Struct type '{customType.Name}' is not defined");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fields.TryGetValue(fieldAccess.Field, out var fieldType))
|
var field = definition.Fields.FirstOrDefault(f => f.Name == fieldAccess.Field);
|
||||||
|
if (field == null)
|
||||||
{
|
{
|
||||||
throw new TypeCheckingException($"Field '{fieldAccess.Field}' does not exist in struct '{customType.Name}'");
|
throw new TypeCheckingException($"Field '{fieldAccess.Field}' does not exist in struct '{customType.Name}'");
|
||||||
}
|
}
|
||||||
|
|
||||||
return fieldType;
|
return field.Type;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool AreTypesCompatible(NubType sourceType, NubType targetType)
|
private static bool AreTypesCompatible(NubType sourceType, NubType targetType)
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ public abstract class NubType
|
|||||||
return new NubPrimitiveType(kind.Value);
|
return new NubPrimitiveType(kind.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new NubCustomType(s);
|
return new NubStructType(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Equals(object? obj) => obj is NubType item && Name.Equals(item.Name);
|
public override bool Equals(object? obj) => obj is NubType item && Name.Equals(item.Name);
|
||||||
@@ -26,16 +26,11 @@ public abstract class NubType
|
|||||||
public override string ToString() => Name;
|
public override string ToString() => Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class NubCustomType(string name) : NubType(name);
|
public class NubStructType(string name) : NubType(name);
|
||||||
|
|
||||||
public class NubPrimitiveType : NubType
|
public class NubPrimitiveType(PrimitiveTypeKind kind) : NubType(KindToString(kind))
|
||||||
{
|
{
|
||||||
public NubPrimitiveType(PrimitiveTypeKind kind) : base(KindToString(kind))
|
public PrimitiveTypeKind Kind { get; } = kind;
|
||||||
{
|
|
||||||
Kind = kind;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PrimitiveTypeKind Kind { get; }
|
|
||||||
|
|
||||||
public static NubPrimitiveType I64 => new(PrimitiveTypeKind.I64);
|
public static NubPrimitiveType I64 => new(PrimitiveTypeKind.I64);
|
||||||
public static NubPrimitiveType I32 => new(PrimitiveTypeKind.I32);
|
public static NubPrimitiveType I32 => new(PrimitiveTypeKind.I32);
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ internal static class Program
|
|||||||
var modules = RunFrontend(input);
|
var modules = RunFrontend(input);
|
||||||
var definitions = modules.SelectMany(f => f.Definitions).ToList();
|
var definitions = modules.SelectMany(f => f.Definitions).ToList();
|
||||||
|
|
||||||
var typeChecker = new TypeChecker();
|
var typeChecker = new TypeChecker(definitions);
|
||||||
typeChecker.TypeCheck(definitions);
|
typeChecker.TypeCheck();
|
||||||
|
|
||||||
var generator = new Generator(definitions);
|
var generator = new Generator(definitions);
|
||||||
var result = generator.Generate();
|
var result = generator.Generate();
|
||||||
|
|||||||
Reference in New Issue
Block a user