Add string debugging

This commit is contained in:
nub31
2026-03-05 22:58:20 +01:00
parent 0e099d0baf
commit c9bf212aa2
4 changed files with 145 additions and 21 deletions

View File

@@ -102,6 +102,7 @@ public class Generator
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h>
"""); """);
@@ -148,6 +149,13 @@ public class Generator
( (
""" """
#define FLAG_STRING_LITERAL 1 #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
struct nub_core_string struct nub_core_string
{ {
@@ -157,54 +165,114 @@ public class Generator
uint32_t flags; uint32_t flags;
}; };
#if STRING_DEBUG
static size_t nub_core_string_allocs = 0;
static size_t nub_core_string_frees = 0;
__attribute__((destructor))
static void string_debug_report(void)
{
fprintf(stderr, "[STR] REPORT allocs=%zu frees=%zu leaks=%zu\n", nub_core_string_allocs, nub_core_string_frees, nub_core_string_allocs - nub_core_string_frees);
}
#endif
static inline void string_rc_inc(struct nub_core_string *string) static inline void string_rc_inc(struct nub_core_string *string)
{ {
if (string == NULL)
{
STR_DBG("INC null string");
return;
}
if (string->flags & FLAG_STRING_LITERAL) if (string->flags & FLAG_STRING_LITERAL)
return; return;
string->ref += 1; string->ref += 1;
STR_DBG("INC: str=%p ref=%u \"%s\"", (void*)string, string->ref, string->data);
} }
static inline void string_rc_dec(struct nub_core_string *string) static inline void string_rc_dec(struct nub_core_string *string)
{ {
if (string == NULL) if (string == NULL)
{
STR_DBG("DEC null string");
return; return;
}
if (string->flags & FLAG_STRING_LITERAL) if (string->flags & FLAG_STRING_LITERAL)
return; return;
if (string->ref == 0)
{
STR_DBG("ERROR: DEC on zero refcount str=%p", (void*)string);
return;
}
string->ref -= 1; string->ref -= 1;
STR_DBG("DEC: str=%p ref=%u \"%s\"", (void*)string, string->ref, string->data);
if (string->ref == 0) if (string->ref == 0)
{ {
free(string->data); STR_DBG("FREE: str=%p data=%p \"%s\"", (void*)string, (void*)string->data, string->data);
free(string);
char *data_ptr = string->data;
struct nub_core_string *str_ptr = string;
#if STRING_DEBUG
nub_core_string_frees++;
memset(data_ptr, 0xDD, str_ptr->length);
memset(str_ptr, 0xDD, sizeof(*str_ptr));
#endif
free(data_ptr);
free(str_ptr);
} }
} }
static inline struct nub_core_string *string_concat(struct nub_core_string *left, struct nub_core_string *right) static inline struct nub_core_string *string_concat(struct nub_core_string *left, struct nub_core_string *right)
{ {
size_t new_length = left->length + right->length; size_t new_length = left->length + right->length;
struct nub_core_string *result = malloc(sizeof(struct nub_core_string)); struct nub_core_string *result = malloc(sizeof(struct nub_core_string));
result->data = malloc(new_length + 1); result->data = malloc(new_length + 1);
memcpy(result->data, left->data, left->length); memcpy(result->data, left->data, left->length);
memcpy(result->data + left->length, right->data, right->length); memcpy(result->data + left->length, right->data, right->length);
result->data[new_length] = '\0'; result->data[new_length] = '\0';
result->length = new_length; result->length = new_length;
result->ref = 1; result->ref = 1;
result->flags = 0; result->flags = 0;
#if STRING_DEBUG
nub_core_string_allocs++;
STR_DBG("NEW concat: str=%p ref=%u \"%s\"", (void*)result, result->ref, result->data);
#endif
return result; return result;
} }
static inline struct nub_core_string *string_from_cstr(const char* cstr) static inline struct nub_core_string *string_from_cstr(char* cstr)
{ {
size_t len = strlen(cstr); size_t len = strlen(cstr);
struct nub_core_string *result = malloc(sizeof(struct nub_core_string)); struct nub_core_string *result = malloc(sizeof(struct nub_core_string));
result->data = malloc(len + 1); result->data = malloc(len + 1);
memcpy(result->data, cstr, len + 1); memcpy(result->data, cstr, len + 1);
result->length = len; result->length = len;
result->ref = 1; result->ref = 1;
result->flags = 0; result->flags = 0;
#if STRING_DEBUG
nub_core_string_allocs++;
STR_DBG("NEW from_cstr: str=%p ref=%u \"%s\"", (void*)result, result->ref, result->data);
#endif
return result; return result;
} }
@@ -491,6 +559,7 @@ public class Generator
TypedNodeExpressionStringLiteral expression => EmitExpressionStringLiteral(expression), TypedNodeExpressionStringLiteral expression => EmitExpressionStringLiteral(expression),
TypedNodeExpressionStructLiteral expression => EmitExpressionStructLiteral(expression), TypedNodeExpressionStructLiteral expression => EmitExpressionStructLiteral(expression),
TypedNodeExpressionEnumLiteral expression => EmitExpressionEnumLiteral(expression), TypedNodeExpressionEnumLiteral expression => EmitExpressionEnumLiteral(expression),
TypedNodeExpressionStringConstructor expression => EmitExpressionStringConstructor(expression),
TypedNodeExpressionStructMemberAccess expression => EmitExpressionMemberAccess(expression), TypedNodeExpressionStructMemberAccess expression => EmitExpressionMemberAccess(expression),
TypedNodeExpressionStringLength expression => EmitExpressionStringLength(expression), TypedNodeExpressionStringLength expression => EmitExpressionStringLength(expression),
TypedNodeExpressionStringPointer expression => EmitExpressionStringPointer(expression), TypedNodeExpressionStringPointer expression => EmitExpressionStringPointer(expression),
@@ -562,7 +631,7 @@ public class Generator
{ {
var name = Tmp(); var name = Tmp();
referencedStringLiterals.Add(name, expression.Value.Value); referencedStringLiterals.Add(name, expression.Value.Value);
return $"&{name}"; return $"(&{name})";
} }
private string EmitExpressionStructLiteral(TypedNodeExpressionStructLiteral expression) private string EmitExpressionStructLiteral(TypedNodeExpressionStructLiteral expression)
@@ -616,6 +685,15 @@ public class Generator
return name; return name;
} }
private string EmitExpressionStringConstructor(TypedNodeExpressionStringConstructor expression)
{
var name = Tmp();
scopes.Peek().DeconstructableNames.Add((name, expression.Type));
var value = EmitExpression(expression.Value);
writer.WriteLine($"{CType(expression.Type, name)} = string_from_cstr({value});");
return name;
}
private string EmitExpressionMemberAccess(TypedNodeExpressionStructMemberAccess expression) private string EmitExpressionMemberAccess(TypedNodeExpressionStructMemberAccess expression)
{ {
var target = EmitExpression(expression.Target); var target = EmitExpression(expression.Target);

View File

@@ -409,30 +409,45 @@ public class Parser
{ {
var type = ParseType(); var type = ParseType();
if (TryExpectSymbol(Symbol.OpenParen)) if (type is NodeTypeString)
{ {
ExpectSymbol(Symbol.OpenParen);
var value = ParseExpression(); var value = ParseExpression();
ExpectSymbol(Symbol.CloseParen); ExpectSymbol(Symbol.CloseParen);
expr = new NodeExpressionEnumLiteral(TokensFrom(startIndex), type, value); expr = new NodeExpressionStringConstructor(TokensFrom(startIndex), value);
} }
else if (TryExpectSymbol(Symbol.OpenCurly)) else if (type is NodeTypeNamed namedType)
{ {
var initializers = new List<NodeExpressionStructLiteral.Initializer>(); if (TryExpectSymbol(Symbol.OpenParen))
while (!TryExpectSymbol(Symbol.CloseCurly))
{ {
var initializerStartIndex = startIndex; var value = ParseExpression();
var fieldName = ExpectIdent(); ExpectSymbol(Symbol.CloseParen);
ExpectSymbol(Symbol.Equal);
var fieldValue = ParseExpression();
initializers.Add(new NodeExpressionStructLiteral.Initializer(TokensFrom(initializerStartIndex), fieldName, fieldValue));
}
expr = new NodeExpressionStructLiteral(TokensFrom(startIndex), null, initializers); expr = new NodeExpressionEnumLiteral(TokensFrom(startIndex), namedType, value);
}
else if (TryExpectSymbol(Symbol.OpenCurly))
{
var initializers = new List<NodeExpressionStructLiteral.Initializer>();
while (!TryExpectSymbol(Symbol.CloseCurly))
{
var initializerStartIndex = startIndex;
var fieldName = ExpectIdent();
ExpectSymbol(Symbol.Equal);
var fieldValue = ParseExpression();
initializers.Add(new NodeExpressionStructLiteral.Initializer(TokensFrom(initializerStartIndex), fieldName, fieldValue));
}
expr = new NodeExpressionStructLiteral(TokensFrom(startIndex), null, initializers);
}
else
{
expr = new NodeExpressionEnumLiteral(TokensFrom(startIndex), namedType, null);
}
} }
else else
{ {
expr = new NodeExpressionEnumLiteral(TokensFrom(startIndex), type, null); throw BasicError($"Expected named type or string", type);
} }
} }
else else
@@ -740,6 +755,11 @@ public class Parser
{ {
return new CompileException(Diagnostic.Error(message).At(fileName, ident).Build()); return new CompileException(Diagnostic.Error(message).At(fileName, ident).Build());
} }
private CompileException BasicError(string message, Node? node)
{
return new CompileException(Diagnostic.Error(message).At(fileName, node).Build());
}
} }
public class Ast(string fileName, TokenIdent moduleName, List<NodeDefinition> definitions) public class Ast(string fileName, TokenIdent moduleName, List<NodeDefinition> definitions)
@@ -893,9 +913,9 @@ public class NodeExpressionBoolLiteral(List<Token> tokens, TokenBoolLiteral valu
public TokenBoolLiteral Value { get; } = value; public TokenBoolLiteral Value { get; } = value;
} }
public class NodeExpressionStructLiteral(List<Token> tokens, NodeType? type, List<NodeExpressionStructLiteral.Initializer> initializers) : NodeExpression(tokens) public class NodeExpressionStructLiteral(List<Token> tokens, NodeTypeNamed? type, List<NodeExpressionStructLiteral.Initializer> initializers) : NodeExpression(tokens)
{ {
public NodeType? Type { get; } = type; public NodeTypeNamed? Type { get; } = type;
public List<Initializer> Initializers { get; } = initializers; public List<Initializer> Initializers { get; } = initializers;
public class Initializer(List<Token> tokens, TokenIdent name, NodeExpression value) : Node(tokens) public class Initializer(List<Token> tokens, TokenIdent name, NodeExpression value) : Node(tokens)
@@ -905,12 +925,17 @@ public class NodeExpressionStructLiteral(List<Token> tokens, NodeType? type, Lis
} }
} }
public class NodeExpressionEnumLiteral(List<Token> tokens, NodeType type, NodeExpression? value) : NodeExpression(tokens) public class NodeExpressionEnumLiteral(List<Token> tokens, NodeTypeNamed type, NodeExpression? value) : NodeExpression(tokens)
{ {
public NodeType Type { get; } = type; public NodeTypeNamed Type { get; } = type;
public NodeExpression? Value { get; } = value; public NodeExpression? Value { get; } = value;
} }
public class NodeExpressionStringConstructor(List<Token> tokens, NodeExpression value) : NodeExpression(tokens)
{
public NodeExpression Value { get; } = value;
}
public class NodeExpressionMemberAccess(List<Token> tokens, NodeExpression target, TokenIdent name) : NodeExpression(tokens) public class NodeExpressionMemberAccess(List<Token> tokens, NodeExpression target, TokenIdent name) : NodeExpression(tokens)
{ {
public NodeExpression Target { get; } = target; public NodeExpression Target { get; } = target;

View File

@@ -263,6 +263,7 @@ public class TypeChecker
NodeExpressionStringLiteral expression => CheckExpressionStringLiteral(expression, expectedType), NodeExpressionStringLiteral expression => CheckExpressionStringLiteral(expression, expectedType),
NodeExpressionStructLiteral expression => CheckExpressionStructLiteral(expression, expectedType), NodeExpressionStructLiteral expression => CheckExpressionStructLiteral(expression, expectedType),
NodeExpressionEnumLiteral expression => CheckExpressionEnumLiteral(expression, expectedType), NodeExpressionEnumLiteral expression => CheckExpressionEnumLiteral(expression, expectedType),
NodeExpressionStringConstructor expression => CheckExpressionStringConstructor(expression, expectedType),
_ => throw new ArgumentOutOfRangeException(nameof(node)) _ => throw new ArgumentOutOfRangeException(nameof(node))
}; };
} }
@@ -651,6 +652,17 @@ public class TypeChecker
return new TypedNodeExpressionEnumLiteral(expression.Tokens, type, value); return new TypedNodeExpressionEnumLiteral(expression.Tokens, type, value);
} }
private TypedNodeExpressionStringConstructor CheckExpressionStringConstructor(NodeExpressionStringConstructor expression, NubType? expectedType)
{
var stringPoitnerType = NubTypePointer.Get(NubTypeUInt.Get(8));
var value = CheckExpression(expression.Value, stringPoitnerType);
if (!value.Type.IsAssignableTo(stringPoitnerType))
throw BasicError($"Value of string constructor must be assignable to {stringPoitnerType}", value);
return new TypedNodeExpressionStringConstructor(expression.Tokens, NubTypeString.Instance, value);
}
private NubType ResolveType(NodeType node) private NubType ResolveType(NodeType node)
{ {
return node switch return node switch
@@ -932,6 +944,11 @@ public class TypedNodeExpressionEnumLiteral(List<Token> tokens, NubType type, Ty
public TypedNodeExpression? Value { get; } = value; public TypedNodeExpression? Value { get; } = value;
} }
public class TypedNodeExpressionStringConstructor(List<Token> tokens, NubType type, TypedNodeExpression value) : TypedNodeExpression(tokens, type)
{
public TypedNodeExpression Value { get; } = value;
}
public class TypedNodeExpressionStructMemberAccess(List<Token> tokens, NubType type, TypedNodeExpression target, TokenIdent name) : TypedNodeExpression(tokens, type) public class TypedNodeExpressionStructMemberAccess(List<Token> tokens, NubType type, TypedNodeExpression target, TokenIdent name) : TypedNodeExpression(tokens, type)
{ {
public TypedNodeExpression Target { get; } = target; public TypedNodeExpression Target { get; } = target;

View File

@@ -16,6 +16,10 @@ func main(): i32 {
let message = getMessage() let message = getMessage()
let newStr = new string("cstring".ptr)
core::println(newStr)
match message { match message {
Quit { Quit {
core::println("quit") core::println("quit")