|
|
|
|
@@ -99,8 +99,6 @@ public class Generator
|
|
|
|
|
#include <stdint.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
|
|
#define FLAG_STRING_LITERAL 1
|
|
|
|
|
|
|
|
|
|
""");
|
|
|
|
|
|
|
|
|
|
while (referencedTypes.Count != 0)
|
|
|
|
|
@@ -132,11 +130,48 @@ public class Generator
|
|
|
|
|
{
|
|
|
|
|
writer.WriteLine("char *data;");
|
|
|
|
|
writer.WriteLine("size_t length;");
|
|
|
|
|
writer.WriteLine("uint32_t ref;");
|
|
|
|
|
writer.WriteLine("int32_t ref;");
|
|
|
|
|
writer.WriteLine("uint32_t flags;");
|
|
|
|
|
}
|
|
|
|
|
writer.WriteLine("};");
|
|
|
|
|
writer.WriteLine();
|
|
|
|
|
|
|
|
|
|
writer.WriteLine("#define FLAG_STRING_LITERAL 1");
|
|
|
|
|
writer.WriteLine();
|
|
|
|
|
|
|
|
|
|
writer.WriteLine($"static inline void rc_inc({CType(NubTypeString.Instance, "string")})");
|
|
|
|
|
writer.WriteLine("{");
|
|
|
|
|
using (writer.Indent())
|
|
|
|
|
{
|
|
|
|
|
writer.WriteLine($"string->ref += 1;");
|
|
|
|
|
}
|
|
|
|
|
writer.WriteLine("}");
|
|
|
|
|
writer.WriteLine();
|
|
|
|
|
|
|
|
|
|
writer.WriteLine($"static inline void rc_dec({CType(NubTypeString.Instance, "string")})");
|
|
|
|
|
writer.WriteLine("{");
|
|
|
|
|
using (writer.Indent())
|
|
|
|
|
{
|
|
|
|
|
writer.WriteLine($"string->ref -= 1;");
|
|
|
|
|
writer.WriteLine($"if (string->ref <= 0)");
|
|
|
|
|
writer.WriteLine("{");
|
|
|
|
|
using (writer.Indent())
|
|
|
|
|
{
|
|
|
|
|
writer.WriteLine($"if ((string->flags & FLAG_STRING_LITERAL) == 0)");
|
|
|
|
|
writer.WriteLine("{");
|
|
|
|
|
using (writer.Indent())
|
|
|
|
|
{
|
|
|
|
|
writer.WriteLine($"free(string->data);");
|
|
|
|
|
}
|
|
|
|
|
writer.WriteLine("}");
|
|
|
|
|
writer.WriteLine($"free(string);");
|
|
|
|
|
}
|
|
|
|
|
writer.WriteLine("}");
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
writer.WriteLine("}");
|
|
|
|
|
writer.WriteLine();
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case NubTypeStruct structType:
|
|
|
|
|
@@ -302,7 +337,7 @@ public class Generator
|
|
|
|
|
var value = EmitExpression(statement.Value);
|
|
|
|
|
EmitCopyConstructor(value, statement.Value.Type);
|
|
|
|
|
writer.WriteLine($"{CType(statement.Type, statement.Name.Ident)} = {value};");
|
|
|
|
|
scopes.Peek().Locals.Add((statement.Name.Ident, statement.Type));
|
|
|
|
|
scopes.Peek().DeconstructableNames.Add((statement.Name.Ident, statement.Type));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void EmitStatementAssignment(TypedNodeStatementAssignment statement)
|
|
|
|
|
@@ -397,7 +432,7 @@ public class Generator
|
|
|
|
|
|
|
|
|
|
private string EmitExpression(TypedNodeExpression node)
|
|
|
|
|
{
|
|
|
|
|
return node switch
|
|
|
|
|
var value = node switch
|
|
|
|
|
{
|
|
|
|
|
TypedNodeExpressionBinary expression => EmitExpressionBinary(expression),
|
|
|
|
|
TypedNodeExpressionUnary expression => EmitExpressionUnary(expression),
|
|
|
|
|
@@ -414,6 +449,10 @@ public class Generator
|
|
|
|
|
TypedNodeExpressionFuncCall expression => EmitExpressionFuncCall(expression),
|
|
|
|
|
_ => throw new ArgumentOutOfRangeException(nameof(node), node, null)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var tmp = TmpName();
|
|
|
|
|
writer.WriteLine($"{CType(node.Type, tmp)} = {value};");
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string EmitExpressionBinary(TypedNodeExpressionBinary expression)
|
|
|
|
|
@@ -457,7 +496,7 @@ public class Generator
|
|
|
|
|
private string EmitExpressionStringLiteral(TypedNodeExpressionStringLiteral expression)
|
|
|
|
|
{
|
|
|
|
|
var name = TmpName();
|
|
|
|
|
scopes.Peek().Locals.Add((name, expression.Type));
|
|
|
|
|
scopes.Peek().DeconstructableNames.Add((name, expression.Type));
|
|
|
|
|
|
|
|
|
|
var variable = CType(expression.Type, name);
|
|
|
|
|
|
|
|
|
|
@@ -472,21 +511,30 @@ public class Generator
|
|
|
|
|
|
|
|
|
|
private string EmitExpressionStructLiteral(TypedNodeExpressionStructLiteral expression)
|
|
|
|
|
{
|
|
|
|
|
var name = TmpName();
|
|
|
|
|
scopes.Peek().DeconstructableNames.Add((name, expression.Type));
|
|
|
|
|
|
|
|
|
|
var initializerValues = new Dictionary<string, string>();
|
|
|
|
|
|
|
|
|
|
foreach (var initializer in expression.Initializers)
|
|
|
|
|
{
|
|
|
|
|
var values = EmitExpression(initializer.Value);
|
|
|
|
|
initializerValues[initializer.Name.Ident] = values;
|
|
|
|
|
var value = EmitExpression(initializer.Value);
|
|
|
|
|
EmitCopyConstructor(value, initializer.Value.Type);
|
|
|
|
|
initializerValues[initializer.Name.Ident] = value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var initializerStrings = initializerValues.Select(x => $".{x.Key} = {x.Value}");
|
|
|
|
|
|
|
|
|
|
return $"({CType(expression.Type)}){{ {string.Join(", ", initializerStrings)} }}";
|
|
|
|
|
writer.WriteLine($"{CType(expression.Type, name)} = ({CType(expression.Type)}){{ {string.Join(", ", initializerStrings)} }};");
|
|
|
|
|
|
|
|
|
|
return name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string EmitExpressionEnumLiteral(TypedNodeExpressionEnumLiteral expression)
|
|
|
|
|
{
|
|
|
|
|
var name = TmpName();
|
|
|
|
|
scopes.Peek().DeconstructableNames.Add((name, expression.Type));
|
|
|
|
|
|
|
|
|
|
var enumVariantType = (NubTypeEnumVariant)expression.Type;
|
|
|
|
|
|
|
|
|
|
if (!moduleGraph.TryResolveType(enumVariantType.EnumType.Module, enumVariantType.EnumType.Name, true, out var info))
|
|
|
|
|
@@ -496,8 +544,11 @@ public class Generator
|
|
|
|
|
var tag = enumInfo.Variants.ToList().FindIndex(x => x.Name == enumVariantType.Variant);
|
|
|
|
|
|
|
|
|
|
var value = EmitExpression(expression.Value);
|
|
|
|
|
EmitCopyConstructor(value, expression.Value.Type);
|
|
|
|
|
|
|
|
|
|
return $"({CType(expression.Type)}){{ .tag = {tag}, .{enumVariantType.Variant} = {value} }}";
|
|
|
|
|
writer.WriteLine($"{CType(expression.Type, name)} = ({CType(expression.Type)}){{ .tag = {tag}, .{enumVariantType.Variant} = {value} }};");
|
|
|
|
|
|
|
|
|
|
return name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string EmitExpressionMemberAccess(TypedNodeExpressionStructMemberAccess expression)
|
|
|
|
|
@@ -568,9 +619,9 @@ public class Generator
|
|
|
|
|
{
|
|
|
|
|
foreach (var scope in scopes.Reverse())
|
|
|
|
|
{
|
|
|
|
|
for (int i = scope.Locals.Count - 1; i >= 0; i--)
|
|
|
|
|
for (int i = scope.DeconstructableNames.Count - 1; i >= 0; i--)
|
|
|
|
|
{
|
|
|
|
|
var (name, type) = scope.Locals[i];
|
|
|
|
|
var (name, type) = scope.DeconstructableNames[i];
|
|
|
|
|
EmitCopyDestructor(name, type);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -578,9 +629,9 @@ public class Generator
|
|
|
|
|
|
|
|
|
|
private void EmitCleanupCurrentScope(Scope scope)
|
|
|
|
|
{
|
|
|
|
|
for (int i = scope.Locals.Count - 1; i >= 0; i--)
|
|
|
|
|
for (int i = scope.DeconstructableNames.Count - 1; i >= 0; i--)
|
|
|
|
|
{
|
|
|
|
|
var (name, type) = scope.Locals[i];
|
|
|
|
|
var (name, type) = scope.DeconstructableNames[i];
|
|
|
|
|
EmitCopyDestructor(name, type);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -590,8 +641,65 @@ public class Generator
|
|
|
|
|
switch (type)
|
|
|
|
|
{
|
|
|
|
|
case NubTypeString:
|
|
|
|
|
writer.WriteLine($"{value}->ref += 1;");
|
|
|
|
|
{
|
|
|
|
|
writer.WriteLine($"rc_inc({value});");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case NubTypeStruct structType:
|
|
|
|
|
{
|
|
|
|
|
if (!moduleGraph.TryResolveType(structType.Module, structType.Name, true, out var info) || info is not Module.TypeInfoStruct structInfo)
|
|
|
|
|
throw new UnreachableException();
|
|
|
|
|
|
|
|
|
|
foreach (var field in structInfo.Fields)
|
|
|
|
|
{
|
|
|
|
|
EmitCopyConstructor($"{value}.{field.Name}", field.Type);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case NubTypeAnonymousStruct anonymousStructType:
|
|
|
|
|
{
|
|
|
|
|
foreach (var field in anonymousStructType.Fields)
|
|
|
|
|
{
|
|
|
|
|
EmitCopyConstructor($"{value}.{field.Name}", field.Type);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case NubTypeEnum enumType:
|
|
|
|
|
{
|
|
|
|
|
if (!moduleGraph.TryResolveType(enumType.Module, enumType.Name, true, out var info) || info is not Module.TypeInfoEnum enumInfo)
|
|
|
|
|
throw new UnreachableException();
|
|
|
|
|
|
|
|
|
|
writer.WriteLine($"switch ({value}.tag)");
|
|
|
|
|
writer.WriteLine("{");
|
|
|
|
|
using (writer.Indent())
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < enumInfo.Variants.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
Module.TypeInfoEnum.Variant variant = enumInfo.Variants[i];
|
|
|
|
|
|
|
|
|
|
writer.WriteLine($"case {i}:");
|
|
|
|
|
writer.WriteLine("{");
|
|
|
|
|
using (writer.Indent())
|
|
|
|
|
{
|
|
|
|
|
EmitCopyConstructor($"{value}.{variant.Name}", variant.Type);
|
|
|
|
|
writer.WriteLine("break;");
|
|
|
|
|
}
|
|
|
|
|
writer.WriteLine("}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
writer.WriteLine("}");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case NubTypeEnumVariant enumVariantType:
|
|
|
|
|
{
|
|
|
|
|
if (!moduleGraph.TryResolveType(enumVariantType.EnumType.Module, enumVariantType.EnumType.Name, true, out var info) || info is not Module.TypeInfoEnum enumInfo)
|
|
|
|
|
throw new UnreachableException();
|
|
|
|
|
|
|
|
|
|
var variant = enumInfo.Variants.First(x => x.Name == enumVariantType.Variant);
|
|
|
|
|
|
|
|
|
|
EmitCopyConstructor($"{value}.{variant.Name}", variant.Type);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -600,22 +708,65 @@ public class Generator
|
|
|
|
|
switch (type)
|
|
|
|
|
{
|
|
|
|
|
case NubTypeString:
|
|
|
|
|
writer.WriteLine($"{value}->ref -= 1;");
|
|
|
|
|
writer.WriteLine($"if ({value}->ref == 0)");
|
|
|
|
|
{
|
|
|
|
|
writer.WriteLine($"rc_dec({value});");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case NubTypeStruct structType:
|
|
|
|
|
{
|
|
|
|
|
if (!moduleGraph.TryResolveType(structType.Module, structType.Name, true, out var info) || info is not Module.TypeInfoStruct structInfo)
|
|
|
|
|
throw new UnreachableException();
|
|
|
|
|
|
|
|
|
|
foreach (var field in structInfo.Fields)
|
|
|
|
|
{
|
|
|
|
|
EmitCopyDestructor($"{value}.{field.Name}", field.Type);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case NubTypeAnonymousStruct anonymousStructType:
|
|
|
|
|
{
|
|
|
|
|
foreach (var field in anonymousStructType.Fields)
|
|
|
|
|
{
|
|
|
|
|
EmitCopyDestructor($"{value}.{field.Name}", field.Type);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case NubTypeEnum enumType:
|
|
|
|
|
{
|
|
|
|
|
if (!moduleGraph.TryResolveType(enumType.Module, enumType.Name, true, out var info) || info is not Module.TypeInfoEnum enumInfo)
|
|
|
|
|
throw new UnreachableException();
|
|
|
|
|
|
|
|
|
|
writer.WriteLine($"switch ({value}.tag)");
|
|
|
|
|
writer.WriteLine("{");
|
|
|
|
|
using (writer.Indent())
|
|
|
|
|
{
|
|
|
|
|
writer.WriteLine($"if (({value}->flags & FLAG_STRING_LITERAL) == 0)");
|
|
|
|
|
writer.WriteLine("{");
|
|
|
|
|
using (writer.Indent())
|
|
|
|
|
for (int i = 0; i < enumInfo.Variants.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
writer.WriteLine($"free({value}->data);");
|
|
|
|
|
var variant = enumInfo.Variants[i];
|
|
|
|
|
|
|
|
|
|
writer.WriteLine($"case {i}:");
|
|
|
|
|
writer.WriteLine("{");
|
|
|
|
|
using (writer.Indent())
|
|
|
|
|
{
|
|
|
|
|
EmitCopyDestructor($"{value}.{variant.Name}", variant.Type);
|
|
|
|
|
writer.WriteLine("break;");
|
|
|
|
|
}
|
|
|
|
|
writer.WriteLine("}");
|
|
|
|
|
}
|
|
|
|
|
writer.WriteLine("}");
|
|
|
|
|
writer.WriteLine($"free({value});");
|
|
|
|
|
}
|
|
|
|
|
writer.WriteLine("}");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case NubTypeEnumVariant enumVariantType:
|
|
|
|
|
{
|
|
|
|
|
if (!moduleGraph.TryResolveType(enumVariantType.EnumType.Module, enumVariantType.EnumType.Name, true, out var info) || info is not Module.TypeInfoEnum enumInfo)
|
|
|
|
|
throw new UnreachableException();
|
|
|
|
|
|
|
|
|
|
var variant = enumInfo.Variants.First(x => x.Name == enumVariantType.Variant);
|
|
|
|
|
|
|
|
|
|
EmitCopyDestructor($"{value}.{variant.Name}", variant.Type);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -633,7 +784,7 @@ public class Generator
|
|
|
|
|
|
|
|
|
|
private class Scope
|
|
|
|
|
{
|
|
|
|
|
public List<(string Name, NubType Type)> Locals { get; } = [];
|
|
|
|
|
public List<(string Name, NubType Type)> DeconstructableNames { get; } = [];
|
|
|
|
|
public bool Unreachable { get; set; }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|