Built-in Functions
Complete reference for all built-in functions.
Output Functions
| Function | Description |
|---|---|
say($value) | Print value with newline |
print($value) | Print value without newline |
warn($msg) | Print warning to stderr |
die($msg) | Print error and exit |
String Functions
| Function | Description |
|---|---|
strlen($str) | Return string length |
substr($str, $start, $len) | Extract substring |
index($str, $substr) | Find first occurrence, -1 if not found |
rindex($str, $substr) | Find last occurrence |
uc($str) | Convert to uppercase |
lc($str) | Convert to lowercase |
ucfirst($str) | Uppercase first character |
lcfirst($str) | Lowercase first character |
trim($str) | Remove leading/trailing whitespace |
split($sep, $str) | Split string into array |
join($sep, @arr) | Join array into string |
chr($code) | Character from ASCII code |
ord($char) | ASCII code from character |
sprintf($fmt, ...) | Formatted string (like C sprintf) |
stringify($val) | Convert value to string |
String Repetition Operator (x)
The x operator repeats a string a given number of times. It has the same precedence as *, /, and %.
my str $dashes = "-" x 40;
say($dashes); # "----------------------------------------"
my str $ab = "ab" x 3;
say($ab); # "ababab"
# Useful for formatting
say("=" x 60);
say(" Report Title");
say("=" x 60);
Transliteration (tr///, y///)
The tr/// operator (alias y///) performs character-by-character transliteration. Unlike s///, it does not use regex — it maps individual characters from one set to another.
| Syntax | Description |
|---|---|
$str =~ tr/abc/xyz/; | Replace a with x, b with y, c with z (modifies in place) |
$str =~ y/abc/xyz/; | Same as tr/// (Perl alias) |
my str $new = ($str =~ tr/abc/xyz/r); | Return new string instead of modifying (with /r flag) |
Flags
| Flag | Description |
|---|---|
c | Complement — transliterate characters NOT in the search list |
d | Delete — delete characters with no replacement |
s | Squeeze — collapse duplicate replaced characters into one |
r | Return — return new string, do not modify original |
my str $text = "Hello World";
# ROT13
$text =~ tr/A-Za-z/N-ZA-Mn-za-m/;
say($text); # "Uryyb Jbeyq"
# Lowercase to uppercase
my str $upper = "hello";
$upper =~ tr/a-z/A-Z/;
say($upper); # "HELLO"
# Delete digits
my str $nodigits = "abc123def456";
$nodigits =~ tr/0-9//d;
say($nodigits); # "abcdef"
# Squeeze repeated spaces
my str $spaced = "hello world";
$spaced =~ tr/ / /s;
say($spaced); # "hello world"
# Return modified copy (original unchanged)
my str $original = "hello";
my str $copy = ($original =~ tr/a-z/A-Z/r);
say($original); # "hello" (unchanged)
say($copy); # "HELLO"
Examples
my str $s = " Hello World ";
say(strlen($s)); # 15
say(trim($s)); # "Hello World"
say(substr($s, 2, 5)); # "Hello"
say(uc($s)); # " HELLO WORLD "
say(index($s, "World")); # 8
my array @parts = split(" ", trim($s));
say(join("-", @parts)); # "Hello-World"
Array Functions
| Function | Description |
|---|---|
len(@arr) | Return array length |
scalar(@arr) | Return array length (alias for len) |
push(@arr, $val) | Add element to end |
pop(@arr) | Remove and return last element |
shift(@arr) | Remove and return first element |
unshift(@arr, $val) | Add element to beginning |
reverse(@arr) | Reverse array elements in place |
sort(@arr) | Return sorted array |
splice(@arr, $off, $len) | Remove elements, return removed |
splice(@arr, $off, $len, @repl) | Remove and replace with @repl, return removed |
splice() in Detail
The splice() function removes elements from an array and optionally replaces them. It returns an array of the removed elements.
my array @data = (10, 20, 30, 40, 50);
# Remove 2 elements starting at index 1
my array @removed = splice(@data, 1, 2);
# @removed = (20, 30), @data = (10, 40, 50)
# Replace 1 element at index 1 with two new elements
my array @arr = ("a", "b", "c", "d");
my array @repl = ("X", "Y");
splice(@arr, 1, 1, @repl);
# @arr = ("a", "X", "Y", "c", "d")
# Insert without removing (len = 0)
my array @list = (1, 2, 5);
my array @insert = (3, 4);
splice(@list, 2, 0, @insert);
# @list = (1, 2, 3, 4, 5)
Array Memory Management
| Function | Description |
|---|---|
core::array_capacity(@arr) | Get current allocated capacity |
core::array_reserve(@arr, $n) | Ensure capacity for at least $n elements |
core::array_shrink(@arr) | Shrink capacity to match length |
Pre-allocating Arrays
For performance, pre-allocate arrays when you know the approximate size:
my array @data[1000]; # Pre-allocate for 1000 elements
for (my int $i = 0; $i < 1000; $i++) {
push(@data, $i); # No reallocation needed
}
Array Transformations (map, grep, sort)
Strada supports Perl-style block expressions for powerful array transformations. The special variable $_ contains the current element.
| Expression | Description |
|---|---|
map { expr } @arr | Transform each element |
grep { cond } @arr | Filter elements where condition is true |
sort { $a <=> $b } @arr | Sort with custom comparison ($a, $b) |
sort @arr | Sort alphabetically (default) |
Map Examples
my array @nums = (1, 2, 3, 4, 5);
# Transform each element (double)
my array @doubled = map { $_ * 2 } @nums;
# Result: (2, 4, 6, 8, 10)
# Transform to strings
my array @strings = map { "Value: " . $_ } @nums;
Map with Fat Arrow (Creating Hashes)
The classic Perl idiom for building lookup hashes works in Strada:
my array @fruits = ("apple", "banana", "cherry");
# Create a lookup hash - the Perl way!
my hash %lookup = map { $_ => 1 } @fruits;
# %lookup is now {"apple" => 1, "banana" => 1, "cherry" => 1}
# Fast membership testing
if (exists($lookup{"apple"})) {
say("Found apple!");
}
The fat arrow $_ => value creates a key-value pair. When assigned to a hash variable, these pairs become hash entries.
Grep Examples
my array @nums = (1, 2, 3, 4, 5, 6);
# Keep only even numbers
my array @evens = grep { $_ % 2 == 0 } @nums;
# Result: (2, 4, 6)
# Keep values greater than 3
my array @big = grep { $_ > 3 } @nums;
# Result: (4, 5, 6)
Sort Examples
my array @nums = (5, 2, 8, 1, 9);
# Sort ascending (numeric) - use spaceship operator
my array @asc = sort { $a <=> $b } @nums;
# Result: (1, 2, 5, 8, 9)
# Sort descending
my array @desc = sort { $b <=> $a } @nums;
# Result: (9, 8, 5, 2, 1)
# Default sort (alphabetical)
my array @alpha = sort @names;
Chaining Operations
my array @data = (5, 2, 8, 1, 9, 3, 7);
# Filter, transform, and sort in one pipeline
my array @result = sort { $a <=> $b } map { $_ * 10 } grep { $_ > 3 } @data;
# Result: (50, 70, 80, 90)
Hash Functions
| Function | Description |
|---|---|
keys(%hash) | Return array of keys |
values(%hash) | Return array of values |
exists(%hash, $key) | Check if key exists (returns 1/0) |
delete(%hash, $key) | Remove key-value pair |
each(%hash) | Return next [key, value] pair; empty array when done |
core::hash_default_capacity($n) | Set default capacity for new hashes |
each() Iterator
The each() function returns the next key-value pair from a hash as a two-element array [key, value]. When all pairs have been returned, it returns an empty array. The iterator resets when all entries have been traversed.
my hash %config = ();
$config{"host"} = "localhost";
$config{"port"} = 8080;
$config{"debug"} = 1;
# Iterate with each()
my array @pair = each(%config);
while (scalar(@pair) > 0) {
say($pair[0] . " = " . $pair[1]);
@pair = each(%config);
}
# Output (order may vary):
# host = localhost
# port = 8080
# debug = 1
Pre-allocating Hashes
Pre-allocate hashes when you know the approximate size:
my hash %cache[500]; # Pre-allocate for ~500 entries
# Or set default for all new hashes:
core::hash_default_capacity(1000);
Hashes automatically resize for O(1) average lookup time.
Type Functions
| Function | Description |
|---|---|
int($val) | Convert to integer |
num($val) | Convert to number |
defined($val) | Check if value is defined |
ref($val) | Return reference type or empty string |
typeof($val) | Return type as string |
bless(\%h, $class) | Associate hash ref with class |
core::weaken($ref) | Make $ref a weak reference (break circular refs) |
core::isweak($ref) | Returns 1 if $ref is weak, 0 otherwise |
File I/O Functions
| Function | Description |
|---|---|
slurp($path) | Read entire file as string |
spew($path, $data) | Write string to file |
core::open($path, $mode) | Open file, return filehandle |
core::open(\$var, $mode) | Open in-memory handle (ref-style, writeback on close) |
core::open_str($content, $mode) | Open in-memory handle from string |
core::str_from_fh($fh) | Extract string from memstream |
core::readline($fh) | Read line from filehandle |
core::read($fd, $len) | Read bytes from fd |
core::write($fd, $data) | Write bytes to fd |
core::close($fd) | Close file descriptor |
core::seek($fd, $pos, $whence) | Seek in file |
core::tell($fd) | Get current position |
core::eof($fd) | Check if at end of file |
core::flush($fd) | Flush file buffer |
select($fh) | Set default filehandle for print/say |
select() — Default Filehandle
The select() function sets the default output filehandle. After calling select($fh), all print() and say() calls without an explicit filehandle will write to $fh instead of stdout.
my scalar $fh = core::open("output.log", "w");
# Redirect print/say to the file
select($fh);
say("This goes to output.log");
print("So does this");
# Restore stdout (pass undef or no argument)
select(undef);
say("Back to stdout");
core::close($fh);
Diamond Operator <$fh>
The diamond operator reads lines from a filehandle or socket. Context determines behavior:
| Syntax | Context | Description |
|---|---|---|
my str $line = <$fh> | Scalar | Read one line (strips newline) |
my array @lines = <$fh> | Array | Read ALL lines into array |
@lines = <$fh> | Array | Read ALL lines (assignment) |
<$sock> | Any | Works with sockets too (strips \r\n) |
Filehandle I/O
Say and print work with filehandles as the first argument:
| Syntax | Description |
|---|---|
say($fh, $text) | Write text with newline to filehandle/socket |
print($fh, $text) | Write text without newline to filehandle/socket |
In-Memory I/O
Read from and write to strings using standard file handle operations. All I/O functions work transparently with in-memory handles.
# Read from a string
my scalar $fh = core::open_str("line1\nline2\n", "r");
my str $line = <$fh>; # "line1"
# Write to a string buffer
my scalar $wfh = core::open_str("", "w");
say($wfh, "hello");
my str $result = core::str_from_fh($wfh); # "hello\n"
# Reference-style (variable updated on close)
my str $output = "";
my scalar $wfh2 = core::open(\$output, "w");
say($wfh2, "data");
core::close($wfh2); # $output = "data\n"
Math Functions (math::)
| Function | Description |
|---|---|
math::abs($n) | Absolute value |
math::floor($n) | Round down |
math::ceil($n) | Round up |
math::round($n) | Round to nearest |
math::sqrt($n) | Square root |
math::pow($base, $exp) | Power |
math::sin($n) | Sine |
math::cos($n) | Cosine |
math::tan($n) | Tangent |
math::log($n) | Natural logarithm |
math::log10($n) | Base-10 logarithm |
math::exp($n) | e^n |
math::rand() | Random number 0-1 |
math::srand($seed) | Seed random generator |
System Functions (core::)
Process Control
| Function | Description |
|---|---|
core::exit($code) | Exit with status code |
core::fork() | Fork process |
core::exec($cmd, @args) | Execute command |
core::system($cmd) | Run shell command |
core::wait() | Wait for child process |
core::waitpid($pid) | Wait for specific process |
core::getpid() | Get process ID |
core::getppid() | Get parent process ID |
core::kill($pid, $sig) | Send signal to process |
Environment
| Function | Description |
|---|---|
core::getenv($name) | Get environment variable |
core::setenv($name, $val) | Set environment variable |
core::getcwd() | Get current directory |
core::chdir($path) | Change directory |
File System
| Function | Description |
|---|---|
core::stat($path) | Get file info |
core::mkdir($path) | Create directory |
core::rmdir($path) | Remove directory |
core::unlink($path) | Delete file |
core::rename($old, $new) | Rename file |
core::readdir($path) | List directory |
core::is_dir($path) | Check if directory |
core::is_file($path) | Check if regular file |
core::realpath($path) | Get absolute path |
core::dirname($path) | Get directory part |
core::basename($path) | Get filename part |
core::glob($pattern) | Glob pattern matching |
Time
| Function | Description |
|---|---|
core::time() | Unix timestamp |
core::localtime($ts) | Convert to local time hash |
core::gmtime($ts) | Convert to GMT hash |
core::sleep($secs) | Sleep for seconds |
core::usleep($usecs) | Sleep for microseconds |
Debugging
| Function | Description |
|---|---|
core::stack_trace() | Get current call stack as string |
Call Context (Dynamic Return Type)
| Function | Description |
|---|---|
core::wantarray() | Returns 1 if called in array context |
core::wantscalar() | Returns 1 if called in scalar context (default) |
core::wanthash() | Returns 1 if called in hash context |
Networking
| Function | Description |
|---|---|
core::socket_server($port) | Create TCP server |
core::socket_accept($fd) | Accept connection |
core::socket_connect($host, $port) | Connect to server |
core::gethostbyname($host) | Resolve hostname |
core::gethostbyname_all($host) | Resolve hostname (all addresses) |
core::gethostname() | Get local hostname |
core::getaddrinfo($host, $port) | Advanced address resolution |
SSL/TLS (ssl::)
Secure socket connections via OpenSSL. Build with: cd lib/ssl && make
| Function | Description |
|---|---|
ssl::connect($host, $port) | Connect to TLS server |
ssl::read($conn, $len) | Read from TLS connection |
ssl::write($conn, $data) | Write to TLS connection |
ssl::close($conn) | Close TLS connection |
ssl::http_get($host, $port, $path) | Simple HTTPS GET request |
SSL Example
my int $conn = ssl::connect("example.com", 443);
ssl::write($conn, "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n");
my str $response = ssl::read($conn, 4096);
ssl::close($conn);
# Or use the convenience function:
my str $page = ssl::http_get("example.com", 443, "/");
UTF-8 Introspection (utf8::)
Perl-compatible UTF-8 introspection functions. In Strada, all strings are stored as raw bytes (typically UTF-8). There is no separate "UTF-8 flag" like Perl.
| Function | Description |
|---|---|
utf8::is_utf8($str) | Returns 1 if string is valid UTF-8, 0 otherwise |
utf8::valid($str) | Alias for is_utf8() |
utf8::encode($str) | No-op (strings are already bytes), returns the string |
utf8::decode($str) | Validates UTF-8; returns 1 if valid, 0 if not |
utf8::upgrade($str) | No-op (strings are already UTF-8), returns the string |
utf8::downgrade($str) | Returns string if ASCII-only, dies on non-ASCII |
utf8::downgrade($str, 1) | With fail_ok=1, returns undef instead of dying |
utf8::unicode_to_native($cp) | Identity mapping on modern systems |
UTF-8 Example
my str $text = "Hello";
say(utf8::is_utf8($text)); # 1 (ASCII is valid UTF-8)
say(utf8::downgrade($text)); # "Hello" (ASCII-only, succeeds)
# Safe downgrade with fail_ok
my scalar $result = utf8::downgrade($text, 1);
if (!defined($result)) {
say("Contains non-ASCII");
}
Signals
| Function | Description |
|---|---|
core::signal($sig, \&handler) | Set signal handler |
core::signal($sig, "IGNORE") | Ignore signal |
core::signal($sig, "DEFAULT") | Reset to default |
Dynamic Loading (FFI)
| Function | Description |
|---|---|
core::dl_open($lib) | Load shared library |
core::dl_sym($handle, $name) | Get symbol address |
core::dl_call_sv($fn, @args) | Call Strada function (returns StradaValue) |
core::dl_call_int_sv($fn, @args) | Call Strada function (returns int) |
core::dl_call_str_sv($fn, @args) | Call Strada function (returns str) |
core::dl_call_void_sv($fn, @args) | Call Strada function (void return) |
core::dl_call_version($fn) | Get library version string |
core::dl_close($handle) | Unload library |
FFI Example
# Load a Strada shared library
my int $lib = core::dl_open("./mylib.so");
my int $fn = core::dl_sym($lib, "my_function");
my scalar $result = core::dl_call_sv($fn, [$arg1, $arg2]);
Library Imports
For cleaner library imports, use import_lib, import_object, or import_archive:
use lib "lib";
import_lib "JSON.so"; # Runtime loading (dlopen)
import_object "Utils.o"; # Static linking
import_archive "DataLib.a"; # Static linking with bundled runtime
# Functions are now available with namespace syntax:
my str $json = JSON::encode(\%data);
my hash %data = JSON::decode($json);
Library Compilation
Compile Strada programs as libraries:
./strada --shared mylib.strada # Creates mylib.so
./strada --object mylib.strada # Creates mylib.o
./strada --static-lib mylib.strada # Creates mylib.a (includes runtime)
C Interop (__C__ Blocks)
Embed raw C code directly in Strada programs using __C__ blocks:
Top-Level Blocks
For includes, globals, and C helper functions:
__C__ {
#include <math.h>
#include <openssl/ssl.h>
static SSL_CTX *g_ctx = NULL;
static int helper(int a, int b) {
return a + b;
}
}
Statement-Level Blocks
Inline C code inside functions with access to Strada variables:
func my_sqrt(num $x) num {
__C__ {
double val = strada_to_num(x);
return strada_new_num(sqrt(val));
}
}
Key C Functions
| Function | Description |
|---|---|
strada_to_int(sv) | Extract int64_t from StradaValue* |
strada_to_num(sv) | Extract double from StradaValue* |
strada_to_str(sv) | Extract string (caller must free!) |
strada_new_int(i) | Create StradaValue* from int64_t |
strada_new_num(n) | Create StradaValue* from double |
strada_new_str(s) | Create StradaValue* from string |
&strada_undef | Return undef value |
Opaque Handle Pattern
Store C pointers in Strada int variables (64-bit):
func open_connection(str $host) int {
__C__ {
char *h = strada_to_str(host);
SSL *conn = connect_ssl(h);
free(h);
// Store pointer as int
return strada_new_int((int64_t)(intptr_t)conn);
}
}
func close_connection(int $handle) void {
__C__ {
// Retrieve pointer from int
SSL *conn = (SSL*)(intptr_t)strada_to_int(handle);
SSL_free(conn);
return &strada_undef;
}
}
JSON Functions
| Function | Description |
|---|---|
json_encode($val) | Convert to JSON string |
json_decode($str) | Parse JSON string |
Package Syntax
| Syntax | Description |
|---|---|
__PACKAGE__ | Current package name (runtime) |
::func() | Call func in current package (compile-time) |
.::func() | Alternate syntax for above |
__PACKAGE__::func() | Explicit form of above |
use overload "+" => "method", ...; | Operator overloading for current package |
Example
package Calculator;
func add(int $a, int $b) int { return $a + $b; }
func compute(int $x, int $y) int {
return ::add($x, $y); # Calls Calculator_add
}
Moose-Style OOP Keywords
Strada provides a declarative OOP system inspired by Perl's Moose. See the OOP page for full details and examples.
| Syntax | Description |
|---|---|
has ro type $name; | Declare read-only attribute with getter |
has rw type $name; | Declare read-write attribute with getter and setter |
has ro type $name (required); | Required attribute (must be passed to constructor) |
has rw type $name = default; | Attribute with default value |
extends Parent; | Inherit from one or more parent classes |
extends Parent1, Parent2; | Multiple inheritance |
with Role; | Compose a role (mixin) into the class |
before "method" func($self) void { } | Run code before a method call |
after "method" func($self) void { } | Run code after a method call |
around "method" func($self) void { } | Wrap a method call entirely |
When a package uses has declarations, the compiler automatically generates a new() constructor that accepts named arguments as alternating key-value pairs. If you define your own new(), the auto-generated one is skipped.
my scalar $obj = MyClass::new("name", "value", "age", 30);
core:: Namespace Alias
The core:: namespace is the preferred way to call system functions. It is an alias for the older sys:: namespace. The compiler normalizes core:: to sys:: at compile time, so there is zero overhead. Both namespaces work interchangeably.
| core:: Call (preferred) | Legacy sys:: Call |
|---|---|
core::exit(0) | sys::exit(0) |
core::open($path, "r") | sys::open($path, "r") |
core::time() | sys::time() |
core::getenv("HOME") | sys::getenv("HOME") |
core::fork() | sys::fork() |
Use whichever namespace feels more natural. core:: is recommended for new code as it reads more clearly as "core language functionality."
# These are equivalent:
my int $pid = core::fork();
my int $pid = sys::fork();
my str $home = core::getenv("HOME");
my str $home = sys::getenv("HOME");
my int $now = core::time();
my int $now = sys::time();
Miscellaneous
| Function | Description |
|---|---|
dump($val) | Debug print value structure |
caller() | Get caller information |
eval($code) | Evaluate Strada code string |
$obj->isa($class) | Check if object is instance of class |
$obj->can($method) | Check if object has method |
$obj->$method() | Dynamic method dispatch (name from variable) |
local($var) | Dynamic scoping for our variables |
local() — Dynamic Scoping
The local() function provides dynamic scoping for our (package-global) variables. It saves the current value and automatically restores it when the enclosing scope exits. This is useful for temporarily overriding globals without affecting the rest of the program.
our int $verbose = 0;
func debug_section() void {
local($verbose) = 1; # Temporarily set to 1
do_work(); # $verbose is 1 here
# $verbose automatically restored to 0 on scope exit
}
func do_work() void {
if ($verbose) {
say("Doing work..."); # Prints when called from debug_section
}
}
func main() int {
do_work(); # $verbose is 0, nothing printed
debug_section(); # $verbose is temporarily 1 inside
do_work(); # $verbose is 0 again
return 0;
}
local() provides dynamic scoping — the localized value is visible in the current function and all functions called from it. my provides lexical scoping — the variable is only visible in the current block. local() only works with our variables (package globals).
tie/untie/tied — Tied Hashes
The tie mechanism binds a hash variable to a class, allowing custom behavior for hash operations. When a hash is tied, all accesses (read, write, delete, exists, iteration) are dispatched to methods in the tied class.
| Function | Description |
|---|---|
tie(%hash, "ClassName", @args) | Bind hash to class; calls TIEHASH(@args) |
untie(%hash) | Unbind hash from class |
tied(%hash) | Return the tied object, or undef if not tied |
TIEHASH Methods
The tied class must implement these methods:
| Method | Description |
|---|---|
TIEHASH(@args) | Constructor — called by tie(), returns the tied object |
FETCH($self, $key) | Called when reading: $hash{$key} |
STORE($self, $key, $val) | Called when writing: $hash{$key} = $val |
DELETE($self, $key) | Called for: delete($hash{$key}) |
EXISTS($self, $key) | Called for: exists($hash{$key}) |
FIRSTKEY($self) | Called to start iteration (keys, each) |
NEXTKEY($self, $lastkey) | Called for subsequent keys during iteration |
CLEAR($self) | Called when hash is cleared |
Example: Case-Insensitive Hash
package CIHash;
func TIEHASH() scalar {
my hash %self = ();
$self{"data"} = {};
return bless(\%self, "CIHash");
}
func FETCH(scalar $self, str $key) scalar {
return $self->{"data"}->{lc($key)};
}
func STORE(scalar $self, str $key, scalar $val) void {
$self->{"data"}->{lc($key)} = $val;
}
package main;
func main() int {
my hash %h = ();
tie(%h, "CIHash");
$h{"Name"} = "Alice"; # Calls CIHash::STORE
say($h{"name"}); # Calls CIHash::FETCH -> "Alice"
say($h{"NAME"}); # "Alice" (case insensitive)
untie(%h); # Unbind from class
return 0;
}
When a hash is not tied, hash operations compile to the same code as before — no dispatch checks, no extra branches. The tied mechanism only adds overhead to hashes that are actually tied.
Compiler Flags
The Strada compiler (stradac) and wrapper (strada) support these flags:
| Flag | Description |
|---|---|
-r, --run | Compile and run immediately |
-c, --keep-c | Keep generated .c file |
-g, --debug | Include debug symbols |
-p, --profile | Enable function profiling |
-w, --warnings | Show compiler warnings |
-t, --timing | Show compilation phase timing |
--shared | Compile as shared library (.so) |
-L <path> | Add library search path (high priority) |
-LL <path> | Add library search path (low priority) |
Examples
# Compile and run
./strada -r program.strada
# Compile with debugging
./strada -g program.strada
# Compile with profiling
./strada -p program.strada
./program # Prints profiling report on exit
# Check for warnings
./strada -w program.strada
# Create shared library
./strada --shared mylib.strada # Creates mylib.so