Debugging
Tools for inspecting variables, tracing execution, and profiling performance.
Inspecting Variables
core::dumper() - Pretty Print Any Value
The core::dumper() function returns a human-readable string representation of any value — pass it to say() (or warn()) to print it. (The bare spellings dumper, refcount, stacktrace, ... remain as legacy aliases.)
my hash %user = {
"name" => "Alice",
"age" => 30,
"tags" => ["admin", "developer"]
};
say(core::dumper(\%user));
# Output:
# {
# "name" => "Alice",
# "age" => 30,
# "tags" => [
# "admin",
# "developer"
# ]
# }
Works with all types:
say(core::dumper(42)); # 42
say(core::dumper("hello")); # "hello"
say(core::dumper([1, 2, 3])); # [1, 2, 3]
say(core::dumper(undef)); # undef
core::dumper_str() - Alias
core::dumper_str() is an alias for core::dumper() — both
return the dump as a string:
my str $debug = core::dumper_str(\%data);
Log::debug("Request data: " . $debug);
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])); # "ref" (all references report "ref")
say(typeof({"a" => 1})); # "ref"
say(typeof(\$x)); # "ref"
say(typeof(undef)); # "undef"
core::refcount() - Check Reference Count
Useful for debugging memory issues:
my array @arr = [1, 2, 3];
say(core::refcount(\@arr)); # 1
my scalar $ref = \@arr;
say(core::refcount(\@arr)); # 2
Stack Traces
Automatic Stack Traces on Uncaught Exceptions
When an exception goes uncaught, Strada automatically prints a stack trace:
func deep_function() void {
throw "something went wrong";
}
func middle_function() void {
deep_function();
}
func main() int {
middle_function();
return 0;
}
# Output:
# Uncaught exception: something went wrong
# Stack trace:
# at deep_function (test.strada)
# at middle_function (test.strada)
# at main (test.strada)
core::stack_trace() - Get Stack as String
Returns the current call stack as a string for debugging or logging:
func debug_location() void {
my str $trace = core::stack_trace();
say("Current location:\n" . $trace);
}
try {
risky_operation();
} catch ($e) {
my str $trace = core::stack_trace();
log_error("Error: " . $e . "\nStack:\n" . $trace);
}
caller() - Get Caller Information
core::caller([level]) returns a hash describing a calling
frame, with keys "function", "file", and
"line". Level 0 is the immediate caller, 1 is the caller's caller:
func log_message(str $msg) void {
my str $from = core::caller(0)->{"function"}; # Who called me?
say("[" . $from . "] " . $msg);
}
func process_data() void {
log_message("Processing started");
# Output: [process_data] Processing started
}
Stack levels:
core::caller(0)- the immediate callercore::caller(1)- the caller's callercore::caller(2)- two frames up
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.
Function Profiling (-p)
Compile with -p. The program prints a per-function timing
report (call counts and self/total time) to stderr when it exits —
no code changes needed:
./strada -p myprogram.strada
./myprogram # prints the function profile on exit
Line-Level Profiling (--full-profile)
For line-by-line profiling, compile with --full-profile (writes
strada-prof.out on exit), then render a report:
./strada --full-profile myprogram.strada && ./myprogram
strada-proftext strada-prof.out # text report
strada-profhtml strada-prof.out profhtml/ # HTML report
To profile only a region programmatically, bracket it with the line-profiler API:
core::full_profile_start("region.prof");
# ... code to profile ...
core::full_profile_stop();
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
Line-Level Profiling (Full Profile)
Strada includes a comprehensive line-level profiler (similar to Perl's Devel::NYTProf) for detailed performance analysis.
Quick Start
# Compile with full profiling instrumentation
./strada --full-profile myprogram.strada
# Run the program (writes strada-prof.out on exit)
./myprogram
# Generate a text report
strada-proftext strada-prof.out
# Generate an HTML report with sortable tables and heat-colored source
strada-profhtml strada-prof.out profhtml/
open profhtml/index.html
Difference from -p / --profile
| Flag | Granularity | Output | Use Case |
|---|---|---|---|
-p, --profile | Function-level | Printed to stderr at exit | Quick overview of hot functions |
--full-profile | Line-level | Binary file (strada-prof.out) | Detailed analysis with report tools |
Report Tools
strada-proftext generates a text report to stdout:
strada-proftext strada-prof.out # Full report (functions + lines)
strada-proftext -f strada-prof.out # Functions only
strada-proftext -l strada-prof.out # Lines only
strada-proftext --top 20 strada-prof.out # Show top 20 entries
strada-profhtml generates an HTML report directory:
strada-profhtml strada-prof.out # Output to profhtml/ (default)
strada-profhtml strada-prof.out my-report/ # Custom output directory
Programmatic API
Enable and disable profiling at runtime for targeted analysis:
# Start profiling mid-program with a custom output file
core::full_profile_start("hotpath.prof");
# ... code to profile ...
# Stop profiling and flush data
core::full_profile_stop();
Memory Profiling
Track memory allocations by type:
func main() int {
core::memprof_enable();
# Your code here...
process_data();
core::memprof_report(); # Print memory stats
return 0;
}
Memory Profiler Functions
| Function | Description |
|---|---|
core::memprof_enable() | Start tracking allocations |
core::memprof_disable() | Stop tracking allocations |
core::memprof_report() | Print allocation statistics |
core::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 = core::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 . ":");
core::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
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 |
|---|---|
core::dumper($val) | Pretty-print value to stderr |
core::dumper_str($val) | Return dump as string |
dump($val, $indent) | Dump with indent level |
typeof($val) | Get type name as string |
core::refcount($ref) | Get reference count |
core::stacktrace() | Print call stack |
core::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 |
core::full_profile_start($file) | Start line-level profiling to file |
core::full_profile_stop() | Stop profiling and flush data |