Add string debugging
This commit is contained in:
@@ -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);
|
||||||
|
|||||||
@@ -409,12 +409,22 @@ public class Parser
|
|||||||
{
|
{
|
||||||
var type = ParseType();
|
var type = ParseType();
|
||||||
|
|
||||||
|
if (type is NodeTypeString)
|
||||||
|
{
|
||||||
|
ExpectSymbol(Symbol.OpenParen);
|
||||||
|
var value = ParseExpression();
|
||||||
|
ExpectSymbol(Symbol.CloseParen);
|
||||||
|
|
||||||
|
expr = new NodeExpressionStringConstructor(TokensFrom(startIndex), value);
|
||||||
|
}
|
||||||
|
else if (type is NodeTypeNamed namedType)
|
||||||
|
{
|
||||||
if (TryExpectSymbol(Symbol.OpenParen))
|
if (TryExpectSymbol(Symbol.OpenParen))
|
||||||
{
|
{
|
||||||
var value = ParseExpression();
|
var value = ParseExpression();
|
||||||
ExpectSymbol(Symbol.CloseParen);
|
ExpectSymbol(Symbol.CloseParen);
|
||||||
|
|
||||||
expr = new NodeExpressionEnumLiteral(TokensFrom(startIndex), type, value);
|
expr = new NodeExpressionEnumLiteral(TokensFrom(startIndex), namedType, value);
|
||||||
}
|
}
|
||||||
else if (TryExpectSymbol(Symbol.OpenCurly))
|
else if (TryExpectSymbol(Symbol.OpenCurly))
|
||||||
{
|
{
|
||||||
@@ -432,7 +442,12 @@ public class Parser
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
expr = new NodeExpressionEnumLiteral(TokensFrom(startIndex), type, null);
|
expr = new NodeExpressionEnumLiteral(TokensFrom(startIndex), namedType, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
Reference in New Issue
Block a user