Debugging

Tools for inspecting variables, tracing execution, and profiling performance.

Inspecting Variables

dumper() - Pretty Print Any Value

The dumper() function prints a human-readable representation of any value to stderr:

my hash %user = {
    "name" => "Alice",
    "age" => 30,
    "tags" => ["admin", "developer"]
};

dumper(\%user);
# Output:
# {
#   "name" => "Alice",
#   "age" => 30,
#   "tags" => [
#     "admin",
#     "developer"
#   ]
# }

Works with all types:

dumper(42);              # 42
dumper("hello");         # "hello"
dumper([1, 2, 3]);       # [1, 2, 3]
dumper(undef);           # undef

dumper_str() - Get Dump as String

Returns the dump as a string instead of printing:

my str $debug = dumper_str(\%data);
Log::debug("Request data: " . $debug);

dump() - Compact Output

Similar to dumper() but with an indent parameter for nested output:

dump(\%user, 0);   # Start at indent level 0
dump(\%user, 2);   # Start at indent level 2

typeof() - Get Type Name

Returns the type of a value as a string:

say(typeof(42));           # "int"
say(typeof(3.14));         # "num"
say(typeof("hello"));      # "str"
say(typeof([1, 2]));       # "array"
say(typeof({"a" => 1}));   # "hash"
say(typeof(\$x));          # "ref"
say(typeof(undef));        # "undef"

refcount() - Check Reference Count

Useful for debugging memory issues:

my array @arr = [1, 2, 3];
say(refcount(\@arr));  # 1

my scalar $ref = \@arr;
say(refcount(\@arr));  # 2

Stack Traces

stacktrace() - Print Call Stack

Prints the current call stack to stderr:

func deep_function() void {
    stacktrace();
}

func middle_function() void {
    deep_function();
}

func main() int {
    middle_function();
    return 0;
}

# Output:
# Stack trace:
#   deep_function (test.strada:2)
#   middle_function (test.strada:6)
#   main (test.strada:10)

backtrace() - Alias for stacktrace()

backtrace();  # Same as stacktrace()

stacktrace_str() - Get Stack as String

Returns the stack trace as a string for logging:

my str $trace = stacktrace_str();
Log::error("Error occurred at:\n" . $trace);

caller() - Get Caller Information

Returns the name of the calling function at a given stack level:

func log_message(str $msg) void {
    my str $from = caller(1);  # Who called me?
    say("[" . $from . "] " . $msg);
}

func process_data() void {
    log_message("Processing started");
    # Output: [process_data] Processing started
}

Stack levels:

Compile with Debug Symbols

For better stack traces and GDB debugging, compile with the -g flag:

# Include debug symbols
./strada -g myprogram.strada

# Run with GDB
gdb ./myprogram

Function Profiling

Strada includes a built-in profiler to measure function execution time and call counts.

Enabling the Profiler

func main() int {
    sys::profile_init();  # Initialize profiler

    # Your code here...
    do_work();

    sys::profile_report();  # Print profiling report
    return 0;
}

Manual Function Instrumentation

For fine-grained control, manually instrument functions:

func expensive_operation() void {
    sys::profile_enter("expensive_operation");

    # ... do work ...

    sys::profile_exit("expensive_operation");
}

Profiler Output

The profiler report shows:

# === Function Profile ===
# Function                  Calls    Total(ms)    Avg(ms)
# process_items             1000     2450.32      2.45
# parse_line                50000    1203.45      0.02
# write_output              1000     890.12       0.89

Compiler Timing

To profile the compiler itself, use the -t flag:

./stradac -t input.strada output.c

# Output:
# Lexing:     12.3ms
# Parsing:    45.6ms
# CodeGen:    23.4ms
# Total:      81.3ms

Memory Profiling

Track memory allocations by type:

func main() int {
    sys::memprof_enable();

    # Your code here...
    process_data();

    sys::memprof_report();  # Print memory stats
    return 0;
}

Memory Profiler Functions

Function Description
sys::memprof_enable()Start tracking allocations
sys::memprof_disable()Stop tracking allocations
sys::memprof_report()Print allocation statistics
sys::memprof_reset()Clear all counters

Memory Profile Output

# === Memory Profile ===
# Type       Allocs    Frees     Current    Bytes
# int        15000     14950     50         400
# str        8500      8400      100        12800
# array      200       195       5          240
# hash       150       148       2          128

Assertions

Use die() for assertion-style checks:

func divide(int $a, int $b) int {
    if ($b == 0) {
        die("Assertion failed: divisor cannot be zero");
    }
    return $a / $b;
}

Custom Assert Function

func assert(int $condition, str $msg) void {
    if ($condition == 0) {
        my str $trace = stacktrace_str();
        die("Assertion failed: " . $msg . "\n" . $trace);
    }
}

# Usage
assert(len(@items) > 0, "items array must not be empty");

Logging Patterns

Simple Debug Logger

my int $DEBUG = 1;  # Set to 0 in production

func debug(str $msg) void {
    if ($DEBUG) {
        my str $caller = caller(1);
        warn("[DEBUG] [" . $caller . "] " . $msg);
    }
}

func process() void {
    debug("Starting process");
    # [DEBUG] [process] Starting process
}

Conditional Dumping

func debug_dump(str $label, scalar $value) void {
    if ($DEBUG) {
        warn($label . ":");
        dumper($value);
    }
}

debug_dump("Request", \%request);

Using GDB

For low-level debugging, use GDB with debug symbols:

# Compile with debug info
./strada -g myprogram.strada

# Start GDB
gdb ./myprogram

# Common GDB commands:
(gdb) break main          # Set breakpoint at main
(gdb) run                 # Start execution
(gdb) bt                  # Show backtrace
(gdb) print variable      # Print variable value
(gdb) next                # Step over
(gdb) step                # Step into
(gdb) continue            # Continue execution
GDB Tip Strada values are StradaValue* pointers. Use print *variable to see the struct contents, or call strada_to_str(variable) to get the string representation.

Quick Reference

Function Description
dumper($val)Pretty-print value to stderr
dumper_str($val)Return dump as string
dump($val, $indent)Dump with indent level
typeof($val)Get type name as string
refcount($ref)Get reference count
stacktrace()Print call stack
stacktrace_str()Return call stack as string
caller($level)Get caller function name
warn($msg)Print warning to stderr
die($msg)Print error and exit