diff --git a/compiler/Generator.cs b/compiler/Generator.cs index f76e8ad..cad14eb 100644 --- a/compiler/Generator.cs +++ b/compiler/Generator.cs @@ -93,8 +93,7 @@ public class Generator writer = new IndentedTextWriter(); - writer.WriteLine( -""" + writer.WriteLine(""" #include #include #include @@ -121,29 +120,23 @@ typedef uint64_t u64; typedef int64_t i64; #define FLAG_STRING_LITERAL 1 -#define STRING_DEBUG 1 -#if STRING_DEBUG -#define STR_DBG(fmt, ...) fprintf(stderr, "[STR] " fmt "\n", ##__VA_ARGS__) -#else -#define STR_DBG(fmt, ...) -#endif +#define RC_DBG(fmt, ...) fprintf(stderr, "[RC] " fmt "\n", ##__VA_ARGS__) -#if STRING_DEBUG -static size_t string_allocs = 0; -static size_t string_frees = 0; +static size_t rc_allocs = 0; +static size_t rc_frees = 0; __attribute__((destructor)) static void string_debug_report(void) { - fprintf(stderr, "[STR] REPORT allocs=%zu frees=%zu leaks=%zu\n", string_allocs, string_frees, string_allocs - string_frees); + fprintf(stderr, "[STR] REPORT allocs=%zu frees=%zu leaks=%zu\n", rc_allocs, rc_frees, rc_allocs - rc_frees); } -#endif static inline void string_rc_inc(string *str) { - if (str == NULL) { - STR_DBG("INC null string"); + if (str == NULL) + { + RC_DBG("INC null string"); return; } @@ -152,14 +145,14 @@ static inline void string_rc_inc(string *str) str->ref += 1; - STR_DBG("INC: str=%p ref=%u \"%s\"", (void *)str, str->ref, str->data); + RC_DBG("INC: str=%p ref=%u \"%s\"", (void *)str, str->ref, str->data); } static inline void string_rc_dec(string *str) { if (str == NULL) { - STR_DBG("DEC null string"); + RC_DBG("WRN: DEC null string"); return; } @@ -168,20 +161,18 @@ static inline void string_rc_dec(string *str) if (str->ref == 0) { - STR_DBG("ERROR: DEC on zero refcount str=%p", (void *)str); + RC_DBG("ERR: DEC on zero refcount str=%p", (void *)str); return; } str->ref -= 1; - STR_DBG("DEC: str=%p ref=%u \"%s\"", (void *)str, str->ref, str->data); + RC_DBG("DEC: str=%p ref=%u \"%s\"", (void *)str, str->ref, str->data); - if (str->ref == 0) { - STR_DBG("FREE: str=%p data=%p \"%s\"", (void *)str, (void *)str->data, str->data); - -#if STRING_DEBUG - string_frees++; -#endif + if (str->ref == 0) + { + rc_frees++; + RC_DBG("FREE: str=%p data=%p \"%s\"", (void *)str, (void *)str->data, str->data); free(str->data); free(str); @@ -203,10 +194,8 @@ static inline string *string_concat(string *left, string *right) result->ref = 1; result->flags = 0; -#if STRING_DEBUG - string_allocs++; - STR_DBG("NEW concat: str=%p ref=%u \"%s\"", (void *)result, result->ref, result->data); -#endif + rc_allocs++; + RC_DBG("NEW string_concat: str=%p ref=%u \"%s\"", (void *)result, result->ref, result->data); return result; } @@ -224,10 +213,8 @@ static inline string *string_from_cstr(char *cstr) result->ref = 1; result->flags = 0; -#if STRING_DEBUG - string_allocs++; - STR_DBG("NEW from_cstr: str=%p ref=%u \"%s\"", (void *)result, result->ref, result->data); -#endif + rc_allocs++; + RC_DBG("NEW string_from_cstr: str=%p ref=%u \"%s\"", (void *)result, result->ref, result->data); return result; } @@ -246,8 +233,7 @@ static inline string *string_from_cstr(char *cstr) } \ while (0) -""" -); +"""); while (referencedTypes.Count != 0) { @@ -290,6 +276,8 @@ static inline string *string_from_cstr(char *cstr) { EmitTypeDefinitionIfNotEmitted(arrayType.ElementType); + var name = typeNames[arrayType]; + writer.WriteLine("typedef struct"); writer.WriteLine("{"); using (writer.Indent()) @@ -297,8 +285,90 @@ static inline string *string_from_cstr(char *cstr) writer.WriteLine("size_t count;"); writer.WriteLine("size_t capacity;"); writer.WriteLine($"{CType(arrayType.ElementType)} *items;"); + writer.WriteLine("uint32_t ref;"); } - writer.WriteLine($"}} {typeNames[arrayType]};"); + writer.WriteLine($"}} {name};"); + writer.WriteLine(); + + writer.WriteLine($$""" +static inline void {{name}}_rc_inc({{name}} *array) +{ + if (array == NULL) + { + RC_DBG("WRN: INC null array"); + return; + } + + array->ref += 1; + + RC_DBG("INC: array=%p ref=%u", (void *)array, array->ref); +} + +"""); + + writer.WriteLine($"static inline void {name}_rc_dec({name} *array)"); + writer.WriteLine("{"); + using (writer.Indent()) + { + writer.WriteLine("if (array == NULL)"); + writer.WriteLine("{"); + using (writer.Indent()) + { + writer.WriteLine("RC_DBG(\"WRN: DEC null array\");"); + writer.WriteLine("return;"); + } + writer.WriteLine("}"); + writer.WriteLine(); + writer.WriteLine("if (array->ref == 0)"); + writer.WriteLine("{"); + using (writer.Indent()) + { + writer.WriteLine("RC_DBG(\"ERR: DEC on zero refcount\");"); + writer.WriteLine("return;"); + } + writer.WriteLine("}"); + writer.WriteLine(); + writer.WriteLine("array->ref -= 1;"); + writer.WriteLine(); + writer.WriteLine("RC_DBG(\"DEC: array=%p ref=%u\", (void*)array, array->ref);"); + writer.WriteLine(); + writer.WriteLine("if (array->ref == 0)"); + writer.WriteLine("{"); + using (writer.Indent()) + { + writer.WriteLine("for (size_t i = 0; i < array->count; ++i)"); + writer.WriteLine("{"); + using (writer.Indent()) + { + EmitCopyDestructor("array->items[i]", arrayType.ElementType); + } + writer.WriteLine("}"); + writer.WriteLine(); + writer.WriteLine("rc_frees++;"); + writer.WriteLine("RC_DBG(\"FREE: array=%p data=%p\", (void *)array, (void *)array->items);"); + writer.WriteLine(); + writer.WriteLine("free(array);"); + } + writer.WriteLine("}"); + } + writer.WriteLine("}"); + writer.WriteLine(); + + writer.WriteLine($"static inline {name} *{name}_make()"); + writer.WriteLine("{"); + using (writer.Indent()) + { + writer.WriteLine($"{name} *array = ({name} *)malloc(sizeof({name}));"); + writer.WriteLine("array->ref = 1;"); + writer.WriteLine("array->count = 0;"); + writer.WriteLine("array->capacity = 0;"); + writer.WriteLine("array->items = NULL;"); + writer.WriteLine(); + writer.WriteLine("rc_allocs++;"); + writer.WriteLine($"RC_DBG(\"NEW {name}_make: array=%p ref=%u\", (void *)array, array->ref);"); + writer.WriteLine("return array;"); + } + writer.WriteLine("}"); writer.WriteLine(); break; @@ -535,12 +605,12 @@ static inline string *string_from_cstr(char *cstr) { var index = Tmp(); var array = EmitExpression(statement.Array); - writer.WriteLine($"for (size_t {index} = 0; {index} < {array}.count; ++{index})"); + writer.WriteLine($"for (size_t {index} = 0; {index} < {array}->count; ++{index})"); writer.WriteLine("{"); using (writer.Indent()) { var arrayType = (NubTypeArray)statement.Array.Type; - writer.WriteLine($"{CType(arrayType.ElementType, statement.VariableName.Ident)} = {array}.items[{index}];"); + writer.WriteLine($"{CType(arrayType.ElementType, statement.VariableName.Ident)} = {array}->items[{index}];"); EmitStatement(statement.Body); } writer.WriteLine("}"); @@ -729,13 +799,14 @@ static inline string *string_from_cstr(char *cstr) private string EmitNodeExpressionArrayLiteral(TypedNodeExpressionArrayLiteral expression) { var name = Tmp(); + scopes.Peek().DeconstructableNames.Add((name, expression.Type)); - writer.WriteLine($"{CType(expression.Type, name)} = {{0}};"); + writer.WriteLine($"{CType(expression.Type, name)} = {typeNames[expression.Type]}_make();"); foreach (var value in expression.Values) { var valueName = EmitExpression(value); - writer.WriteLine($"da_append(&{name}, {valueName});"); + writer.WriteLine($"da_append({name}, {valueName});"); } return name; @@ -771,13 +842,13 @@ static inline string *string_from_cstr(char *cstr) private string EmitExpressionArrayCount(TypedNodeExpressionArrayCount expression) { var target = EmitExpression(expression.Target); - return $"{target}.count"; + return $"{target}->count"; } private string EmitExpressionArrayPointer(TypedNodeExpressionArrayPointer expression) { var target = EmitExpression(expression.Target); - return $"{target}.items"; + return $"{target}->items"; } private string EmitNodeExpressionGlobalIdent(TypedNodeExpressionGlobalIdent expression) @@ -815,14 +886,14 @@ static inline string *string_from_cstr(char *cstr) NubTypePointer type => CType(type.To) + (varName != null ? $" *{varName}" : "*"), NubTypeString type => "string" + (varName != null ? $" *{varName}" : "*"), NubTypeFunc type => $"{CType(type.ReturnType)} (*{varName})({string.Join(", ", type.Parameters.Select(p => CType(p)))})", - NubTypeArray type => CTypeNamed(type, varName), + NubTypeArray type => $"{CTypeNamed(type)}" + (varName != null ? $" *{varName}" : "*"), _ => throw new ArgumentOutOfRangeException(nameof(node), node, null) }; } private readonly Dictionary typeNames = []; - private string CTypeNamed(NubType type, string? varName) + private string CTypeNamed(NubType type, string? varName = null) { if (!typeNames.TryGetValue(type, out var name)) { @@ -863,6 +934,11 @@ static inline string *string_from_cstr(char *cstr) { switch (type) { + case NubTypeArray arrayType: + { + writer.WriteLine($"{typeNames[arrayType]}_rc_inc({value});"); + break; + } case NubTypeString: { writer.WriteLine($"string_rc_inc({value});"); @@ -934,6 +1010,11 @@ static inline string *string_from_cstr(char *cstr) { switch (type) { + case NubTypeArray arrayType: + { + writer.WriteLine($"{typeNames[arrayType]}_rc_dec({value});"); + break; + } case NubTypeString: { writer.WriteLine($"string_rc_dec({value});"); diff --git a/examples/program/main.nub b/examples/program/main.nub index cef6d98..8ea56d1 100644 --- a/examples/program/main.nub +++ b/examples/program/main.nub @@ -11,6 +11,10 @@ enum Message { } func main(): i32 { + + let x = new string("test".ptr) + " " + "uwu" + core::println(x) + let messages: []Message = [new Message::Say("first"), new Message::Quit] for message in messages {