Functions
Variables and parameters
Here is how you define a function:
>> fn hello { print "Hello, World!" }
>> hello
Hello, World!
Variables, defined inside functions, don't leak outside of scope:
>> fn hello {
$msg := "Hello, World!"
print $msg
}
>> hello
Hello, World!
>> print $msg
sy: $msg is used, but not declared, use ':=' to declare a new variable
Function can have positional arguments:
>> fn area $radius {
put ($radius ** 2 * 3.14)
}
>> area 10
314
>> area
area: got 0 arguments, but there should be exactly 1
It's possible to restrict incoming parameters by specifying a formatter:
>> fn area (float)$radius {
put ($radius ** 2 * 3.14)
}
(float)$radius will ensure that $radius is
set to a number; this is mostly equivalent to the following:
>> fn area $arg1 {
$radius := $arg1:float
put ($radius ** 2 * 3.14)
}
Except it has better error reporting:
>> area one
area: bad $radius argument: can't parse a float: bad symbol "o"
>> area "10"
314
>> area 10 # 10 is already a number, so it's passed as is
314
Subcommands
Function name can consist of several words, this will automatically create git- or kubectl-style subcommands:
>> $remote := "alice@bob.inc"
>> fn svc restart $name {
ssh $remote systemctl restart $name
}
>> fn svc status $name {
ssh $remote systemctl is-active $name
}
>> svc restart nginx
>> svc status nginx
active
Optional and Variadic Arguments
Positional arguments can be marked optional with ?:
>> fn svc logs $name $lines? {
ssh $remote journalctl -u $name -n ($lines ?? 50)
}
>> svc logs nginx # last 50 lines
>> svc logs nginx 100 # last 100 lines
Binary operator ?? passes $lines through,
if it's not null, otherwise passes its right side — 50.
Formatters and optional arguments combine directly, providing a validated, typed argument with no manual parsing required:
>> fn svc logs $name (int)$lines? {
ssh $remote journalctl -u $name -n ($lines ?? 50)
}
>> svc logs nginx # last 50 lines
>> svc logs nginx 100 # last 100 lines
>> svc logs nginx boo # ERROR
The last function argument can be made variadic with ...
to collect any remaining values into a list. svc restart
can be rewritten this way to accept multiple services:
>> fn svc restart $names... {
ssh $remote systemctl restart $names...
}
It can also be typed:
>> fn sum (float)$nums... {
$sum := 0
for $num in $nums {
$sum += $num
}
put $sum
}
>> sum 1 2 3
6
>> sum "1" "2" "3.1"
6.1
Options
Functions can declare --flag value options. Options must
be declared before any positional arguments and are always optional:
fn compile
-o|--output $file # compiler output object file
-O|--opt (int)$level # optimization level
-g|--debug (bool)$debug # keep debugging information
--std $standard # enforce this standard version
-v|--verbose (bool)$verbose # print more info along the way
$source... # input source files
{
# implementation
}
Options with a (bool) formatter are handled specially:
they require no following parameter, all other options must be followed
by a parameter:
>> compile -o main.o main.rs
>> compile -v -o main.o main.rs
All unset variables are null. --flag=value
syntax is supported, but discouraged, because it forces option value to
be converted to string, which possibly leads to type erasure and
performance penalty.
Defaults are planned for the next release.
Standalone Scripts
When you execute a script, if it has a main function, it
will be called. main will receive all script's arguments.
Here is a small-script that implements two subcommands:
#!/usr/bin/env sy
fn main status { print "All good!" }
fn main launch { print "Launching..." }
Then, if you run it:
>> ./small-script status
All good!
Imports
If you have a file robot.sy in the current directory
like this:
$x, $y := 0, 0
fn move down { $y -= 1 }
fn move up { $y += 1 }
fn move left { $x -= 1 }
fn move right { $x += 1 }
fn report position { put [$x, $y] }
then it can be imported.
The name of the import becomes a prefix, which can be used to call
functions:
>> import robot
>> robot move up
>> robot move left
>> robot move left
>> robot report position
[-2, 1]
Imported files might global variables, i.e. variable defined in the top scope. This variables are initialized, when file is just imported. However, they are not accessible outside of this file — variables always stay private to the file where they are defined.
Each imported file can import other files. The same file can be imported in multiple places, however syshell runtime will load this file only once and reuse it, when it is imported next time.