For version 0.7.0.
To top.

Program structure


This part should give an idea of the over-all look of a Shapes program. Only the first section below is defining the language; the subsequent sections are just advisory.
Sections:    Character encoding, line endings, and indentation    The prelude    Program result    Coding guidelines

Character encoding, line endings, and indentation

The Shapes source shall be encoded using utf-8, and use UNIX style line endings (that is, the new line character alone, byte value 10).
Shapes source is not sensitive to indentation. However, any indentation should be made using the space character only. The tab character is reserved to support indentation of text presented with variable-width fonts.

The prelude

The set of global bindings available to a Shapes program consists of two parts. First, there are the kernel bindings, set up by binary code in the compiler alone. Second, the prelude adds bindings defined in the Shapes language. The prelude resides in the parent environment to the environmet of the input source file, and the kernel bindings reside in the prelude's parent environment.
While the kernel bindings are uniquely defined by the compiler version, the exact contents of the prelude depends on the user's setup. However, there comes a standard prelude with the compiler, so if the user makes no changes to the default, the distinction between kernel bindings and the prelude is of minor importance — except for where to find documentation.
The set of files to evaluate in order to set up the prelude is determined by the Shapes-Namespace.txt files that appear in every directory in the need search path (see syntax.html and man page).
The standard extensions that are part of the standard prelude are marked clearly in the documentation, so these need not be included explicitly.

Program result

The Shapes compiler will run either in shape mode or in blank mode, typically determined by the suffix of the input filename.

Shape mode

Shape mode is selected for input files with suffix .shapes, or when in doubt.
In shape mode, the only necessary aspect to discuss regarding the global structure of a Shapes program is how the graphical output is defined. There are three means for defining the output of a Shapes program:
At least one of the alternatives must be used by the program. It is, however, not necessary that exactly on is used; some combinations are OK due to precedence rules.
It is illegal to both add pages to ..Shapes..IO..•catalog and let the program evaluate to a value. The other combinations are allowed by giving precedence to ..Shapes..IO..•catalog and program value over ..Shapes..IO..•page. Hence, ..Shapes..IO..•page is only used when it is the only alternative in use.
The rationale behind the precedence rule is that ..Shapes..IO..•page may be used to define pages of multi-page documents, and then the rule relieves us from having to clear ..Shapes..IO..•page at the end of the program. Similarly, if one finds that the final content of ..Shapes..IO..•page needs to be transformed for some reason, one may apply the transform to (..Shapes..IO..•page) at the end of the program, without having to clear ..Shapes..IO..•page.

Blank mode

Blank mode is selected for input files with suffix .blank.
In blank mode, the Shapes compiler is not expecting a graphical result to be defined, and will not write any results to output files. In this mode, the program result is not in any standardized format. One common case is a program which just produces output on stdout.

Coding guidelines

This section gives general recommendations on how to organize Shapes source code.

One-liners

The shortest non-empty valid Shapes program I can think of (an empty program is valid in blank mode), is
Shapes..@spot
It produces a circular mark.
This program has the typical structure of a one-liner; it consists just of a pure expression. Being a one-liner, it doesn't contain any ##lookin lexer directive, so the Shapes namespace needs to be prepended to all standard bindings.
A nice application of this is to produce a small label typeset using LaTeX, as shown by the example below.
One-liner
Angry
A typical Shapes program.

Source: show/hide visit
Note that one-liners are often given to the compiler through the stdin stream. Search for stdin on man.html for more information.

A typical Shapes program

Let us discuss the big picture of a typical shape mode program. (Recall that shape mode means that compilation of this program will result in graphics.)
First, a typical program will list a couple of standard extensions, with the lexer directive ##needs.
##needs ..Applications..Blockdraw / blockdraw
If one thinks the font size of TeX labels is too small, this could be a good thing to change next. One may also want to add some LaTeX packages…
##classoption 10pt
##preamble \usepackage{bm}
There are a couple of other lexer directives that could go here, but one being of particular importance is the one which tells in which namespaces to look for identifiers. With these we will be able to write just ignore instead of Shapes..ignore, and longblock instead of Applications..Blockdraw..longblock.
##lookin ..Shapes
##lookin ..Applications..Blockdraw
The leading namespace separator in the ##lookin lexer directive isn't necessary in most cases, but it is recommended to use it anyway to allow any namespaces that really should be given as relative to stand out.
Now, say we don't like some of the default settings of dynamic variables. Then we encapsulate the rest of the program with a couple of dynamic bindings in scope.
  @longblockrx:10mm
& @connectionlw:0.3bp
|
{
/** rest of program goes here, typically without indentation. **/
}
Finally, the code that really produces something is inserted where the dynamic bindings are in scope. As a very simple example, one might insert code like this:
a: [putblockOrigin •page [longblock [TeX `$\bm{a}$´]]]
b: [putblockFarRight •page [longblock [TeX `$\bm{b}$´]] a]
ignore [] [connect •page a b]
Unless something is out of sync, the whole program is included in the example below.
Typical shape mode program
Angry
A typical Shapes program.

Source: show/hide visit

A blank mode Shapes program

Sometimes, one may just be interested in playing around with programming concepts and produce text output to verify the operation. For instance, say that we would like to show somebody how a factorial function can be defined;
factorial: \ n → [if ( n = '0 ) '1 ( n * [factorial n-'1] )]
Shapes..•stdout << [factorial '5] << "{n}
In shape mode, this would not be a valid program since no graphics is produced. The reason is that Shapes is primarily designed for graphics tasks, and in shape mode it should generally be considered an indication of failure if no graphics is produced.
To solve the problem, the primary option would be to run the program in blank mode, by naming the input file with the .blank suffix.
The secondary option would be to end the program with any simple expression that evaluates to a §Drawable, for instance
@spot /** Avoid empty-output error in shape mode. **/
The comment makes it clear that the expression has nothing to do with the main purpose of the program. One advantage of this solution is that the program will work both in shape mode and in blank mode. The complete program is given in the example below.
Text output in shape mode
Angry
A text-producing Shapes program in shape mode must produce graphics as well.

Source: show/hide visit

stdout: show/hide
Get Shapes at SourceForge.net. Fast, secure and Free Open Source software downloads