The Sway Reference Manual/Storing Code in Files

After a while, it gets rather tedious to cut and paste into the Sway interpreter. A more efficient method is to store your program in a text file and then load the file.

I use vim as my text editor. Vim is an editor that was written by programmers for programmers (emacs is another such editor) and serious Computer Scientists and Programmers should learn vim (or emacs).

Your first program
Create a text file named hello.s. The name really doesn't matter and doesn't have to end in .s (the .s is a convention to remind us this file contains Sway source code). Place in the file

println("hello, world!");

Save your work and exit the text editor. Now execute the following command at the system prompt (not the Sway interpreter prompt!):

sway hello.s

You should see the phrase:

hello, world!

displayed on your console. Here's a trace using Linux:

lusth@warka:~$ sway hello.s   hello, world! lusth@warka:~$

The lusth@warka:~$ is my system prompt.

A Neat Macro
One of the more useful things you can do is set up a vim macro. Edit (or create) the file .exrc in your home directory and add these lines:

set ai sm sw=4 map @ :!sway %^V^M

The first line sets some useful parameters: autoindent and showmatch. The sw=4 sets the indentation to four spaces. The next line makes the '@' key, when pressed, run the Sway interpreter on the file you are currently editing (save your work first before tapping the @ key). The ^V^M part of the macro is not the four characters ^ V ^ M, but two characters -v and -m. It's just when you type -v-m, it will display as ^V^M.

Writing Sway Programs
A typical Sway program is composed of two sections. The first section is composed of variable and function definitions. The next section is composed of statements, which are Sway expressions, each of which is (usually) followed by a semicolon.

The ''hello.s' file above was a program with no definitions and a single statement. A Sway program composed only of definitions will usually run with no output to the screen. Such programs are usually written for the express purpose of being included into other programs.

Typically, one of the function definitions is a function named main (by convention); this function takes no arguments. The last line of the program is a call to main. Here is a rewrite of hello.s using that convention.

function main {       println("hello, world!"); }

main;

This version's output is exactly the same as the previous version.

Order of definitions
A function or variable must be defined before it is used. This program will generate an error:

var x = y * y;   var y = 3;

since x can't be given a value until y is defined. This program is legal, however:

function x {       y * y; }

function y {       3;        }

x;

because even though the body of function x refers to function y, function y is defined by the time function x is called (the last statement of the program).

Including code
One can include one Sway module into another by use of the include function:

include("moduleX.s");

where moduleX.s is the name of the file whose Sway definitions you wish to include. Including a module imports all the top level definitions in that module. The statements beyond the definitions in the included module are ignored and are not evaluated.

If moduleX.s has includes, those modules will be included as well.

Preventing multiple includes
Sometimes, in a complex implementation, a module can get included more than once. Usually, this results in multiple definitions of the same item and, while wasteful, usually does not cause any harm. However, consider the case where one module includes the other and vice versa. Here is an example. One module, fact.s, has the following implementation:

include("fib.s"); function fact(n) {       if (n < 2,1,n * fact(n - 1)); }   println("fib(5) is ",fib(5)); println("fact(5) is ",fact(5));

The other module, fib.s, has this code:

include("fact.s"); function fib(n) {       if (n < 2,v,fib(n - 2) * fib(n - 1)); }   println("fib(6) is ",fib(6)); println("fact(6) is ",fact(6));

Trying to run Sway on either module results in an out of memory error, since each file gets included over and over (fib.s includes fact.s which includes fib.s and so on). One can prevent multiple includes by using the includeOnce function. Here is a rewrite of each module.

fact.s
includeOnce(fib.s,"fib.s"); function fact(n) {       if (n < 2,1,n * fact(n - 1)); }   println("fib(5) is ",fib(5)); println("fact(5) is ",fact(5));

fib.s
includeOnce(fact.s,"fact.s"); function fib(n) {       if (n < 2,v,fib(n - 2) * fib(n - 1)); }   println("fib(6) is ",fib(6)); println("fact(6) is ",fact(6));

Running the fact.s program yields:

fib(5) is 5 fact(5) is 120

while running the fib.s program yields:

fib(6) is 8 fact(6) is 720

The first argument passed to the includeOnce function must be a variable, but this variable does not necessarily have to be defined. The includeOnce function checks to see if its first argument has already been defined. If the variable already exists, no further action is taken. If not, includeOnce defines it with a value of :true and then includes the module named by the second argument. Due to Sway's lax naming rules for variable names, most file names (including Unix style paths) without spaces are legal variable names. By convention, the variable name given to includeOnce is the name of the file containing the module; though any variable name will suffice. If there is a name clash, however, and the variable is already declared through some other means, the given module will not be included. The includeOnce function only checks to see if the first argument is defined in the current local scope, so the check against multiple includes will not work if you include once again at a different scope level.

The include and includeOnce function are the only functions that are considered definitions and thus can appear in the definition area of a Sway module. It is legal, however, to call either function in an expression, as in:

x = includeOnce(:module1.s,"module1.s");

Of course, such calls to include and includeOnce are not part of the definition area. In the following example, only the top level definitions from modules B and C are included in A.

A.s
include("B.s"); ...

B.s
include("C.s"); var x;   x = include("D.s");

The definitions from module D.s are not included into A.s since only the definition area of B.s is included in A.s (which causes an include of C.s). The call to include D.s is in the expression area and is ignored when B.s is included.