Skip to content
This repository has been archived by the owner on May 28, 2018. It is now read-only.

dbremner/fortress

Repository files navigation

PROJECT FORTRESS SUBVERSION REPOSITORY
--------------------------------------

This README exists in the top-level directory of the Fortress project.
Information about Fortress can be found at the following web site:

    http://projectfortress.sun.com

If you have Subversion installed, you can check out the Fortress
repository by going to the directory in which you want to check it out
and issuing the following command:

    svn checkout https://projectfortress.sun.com/svn/Community/trunk PFC

(The name "PFC" merely specifies the name of the directory you want
to check the code into.  Feel free to substitute another directory
name if you prefer.)

You'll now have a subdirectory named 'PFC'.  Go into that
directory and you'll see several subdirectories:

Fortify: The Fortify tool for converting Fortress code into LaTeX,
both interactively and in batch mode.  Scripts are provided for
conveniently producing rendered Fortress code in LaTeX documents,
for producing PDF "doc" files from Fortress source code, etc.  See
Fortify/fortify-doc.txt for more information.

ProjectFortress: The Fortress interpreter.  You'll need to build the
interpreter by following the instructions below for setting up your
environment in order to have a complete Fortress installation.

Emacs: A directory holding the Emacs Lisp file fortress-mode.el,
which defines a Fortress mode for Emacs.  To use this file, load
it from your .emacs file with the following command:

    (load (concat (getenv "FORTRESS_HOME")
                  "/contrib/Emacs/fortress-mode.el"))
    (push '("\\.fs[si]$" . fortress-mode) auto-mode-alist)

If you wish to use the Fortify package to format Fortress source code
into LaTeX, you should also add the following to your .emacs (for more
information about fortify, see Fortify/fortify-doc.txt):

    (load (concat (getenv "FORTRESS_HOME")
                  "/Fortify/fortify.el"))

Vim: A directory containing vim script files for syntax highlighting.
To enable syntax highlighting for fortress code copy the sub-directories
under Vim/ to your ~/.vim directory.
  $ mkdir ~/.vim
  $ cp -a Vim/ftdetect Vim/syntax Vim/ftplugin ~/.vim/.
If your cp command does not accept the -a option then use -r
  $ cp -r Vim/ftdetect Vim/syntax Vim/ftplugin ~/.vim/.

You should also add the following line to your ~/.vimrc file
  au BufNewFile,BufRead *.fsi,*.fss set ft=fortress

SpecData: Machine-readable files used by the Fortress Language
Specification (e.g., a list of all reserved words).  Editors and other
tools may also benefit from using these files.  Moreover, all examples
included in the language specification are included in the directory
SpecData/examples.

Specification: A directory containing a PDF of the Fortress Language
Specification, Version 1.0.

Library: The home for all of the Fortress standard libraries.

bin: Shell scripts for our various projects.  These are bash scripts;
you will need an installation of Bash on your system to run them.  To
make these scripts "auto-homing", script "forfoobar" begins with the
line
    FORTRESS_HOME=`${0%forfoobar}fortress_home`
This replaces 'forfoobar' in whatever was used to invoke the script
with 'fortress_home', runs that command, and assigns its output to
FORTRESS_HOME for the remainder of the scripts.  'fortress_home'
determines the location of fortress_home if it is not otherwise
specified.  This command can also be used in your own build files;
for example, if you include the fortify macros in a LaTeX file
    \input{$FORTRESS_HOME/Fortify/fortify-macros}
you might precede the latex command with
    FORTRESS_HOME="`fortress_home`"
It is also possible to set FORTRESS_HOME in your environment, but
if you have multiple versions of Fortress installed this can cause
confusion and build problems.

You will also see the following files:

ant: A small bash script used for invoking the build.xml with
specific Ant options.  (This script defers to the script with the
same name in directory ProjectFortress.)

build.xml: The interpreter build script, written in Ant.  (This
script defers to the script with the same name in the directory
ProjectFortress.)

fortress.properties: This file defines several environment variables
used by the internals of the Fortress interpreter.  (Normally, there is
no reason to override the settings in this file.)


SETTING UP YOUR ENVIRONMENT
---------------------------

We assume you are using an operating system with a Unix-style shell
(for example, Solaris, Linux, Mac OS X, or Cygwin on Windows).  You
will need to have access to the following:

* J2SDK 1.6 or later.  See http://java.sun.com/javase/downloads/index.jsp
* Ant 1.6.5 or later.  See http://ant.apache.org/bindownload.cgi
* Bash version 2.5 or later, installed at /bin/bash.
  See http://www.gnu.org/software/bash/

Assume FORTRESS_HOME points to the PFC directory you checked out.  On
Unix-like systems this should be a matter of using export or setenv.  If
you are using Cygwin, one user reports success with the following
command line for setting FORTRESS_HOME:
  export FORTRESS_HOME=`cygpath -am cygwin/path/to/fortress/install/directory`
e.g.:
  export FORTRESS_HOME=`cygpath -am ${HOME}/tools/fortress`


In your shell startup script, add $FORTRESS_HOME/bin to your path.
The shell scripts in this directory are Bash scripts.  To run them,
you must have Bash accessible in /bin/bash.

Make sure the following environment variables are set in your startup
script:

    JAVA_HOME
    ANT_HOME

(Although our scripts are sometimes able to guess the locations of
JAVA_HOME and ANT_HOME, it is preferred that you set them manually.)

Once all of these environment variables are set, build the interpreter
by going to the directory FORTRESS_HOME and typing the command:

    ./ant clean compile

If that doesn't work, there's a bug in the interpreter; please issue a
bug report.

Once you have built the interpreter, you can call it from any directory,
on any Fortress file, simply by typing one of the following commands at a
command line:

    fortress [walk] [-test] [-debug interpreter] somefile.fss arg...
    fortress help

The first time you run a Fortress program, the static checker is
called on the given file and the results are stored in a cache
directory (by default this cache is kept in default_repository/caches
in the root of your Fortress distribution).  No user-visible object
file is generated.  A file with suffix .fsi should contain a single API
definition.  The name of the API should match the name of the file.
Similarly, a file with the suffix .fss should contain a single
component definition.  The name of the component should match the name
of the file.

A command of the form "fortress walk somefile.fss" checks whether a
cached and up to date result of compiling the given file exists.  If
so, it runs the cached file.  Otherwise, it processes the given file
and runs the result.  This command can be abbreviated as "fortress
somefile.fss".  If the optional flag -test is given, all test
functions defined in the given file are run instead.  If the optional
flag "-debug interpreter" is given, stack traces from the underlying
interpreter are displayed when errors are signaled.

If all else fails, look at the script bin/fortress to see if your system
has peculiarities (for example cygwin requires ; separators in the
classpath).


USING ECLIPSE
-------------
There exists a .project file in the directory ${FORTRESS_HOME}.
Import this project into Eclipse.

There exists a file called ${FORTRESS_HOME}/DOTCLASSPATH in
the repository. Copy this file to ${FORTRESS_HOME}/.classpath.
If you are using the Java 5.0 jdk under Windows or Linux, you will need
to add an entry to ${JAVA_HOME}/lib/tools.jar to the classpath.

Setting up Eclipse to follow the Fortress project coding style
conventions is a two-step process. The following instructions are
known to work on Eclipse 3.4, and should work on Eclipse 3.3 as well.
These will change preferences for all your Eclipse projects.
Open up Eclipse Preferences to start configuring your global
settings. First select General --> Editors --> Text Editors
and make sure the checkbox is enabled for "Insert spaces for tabs".
Second select Java --> Code Style --> Formatter and click on the "Edit..."
button. Change the Tab policy to "Spaces only" and give the profile a new
name (recommended name: "Spaces only").  Click "OK" and you are finished.

DEMO PROGRAMS
-------------

The directory ProjectFortress/demos/ contains some demonstration Fortress
programs.  Among them are:

buffons.fss: Buffon's needle.  Estimates pi using a Monte Carlo
simulation.

lutx.fss: Naive dense LU decomposition.  Demonstrates how to define
new subclasses of Array2.

conjGrad.fss: Conjugate gradient, including the snapshot from the NAS
CG benchmark that you've seen in many Fortress talks.  Uses the Sparse
library for sparse matrices and vectors.

sudoku.fss: Solve a simple sudoku by elimination.  Includes a
tree-based set implementation.

aStar.fss: Generic A* search, accompanied by a specific instance for
solving sudoku that cannot be solved by elimination alone.

Lambda.fss: A simple interpreter for the lambda calculus that permits
top-level binding and reduces to both WNHF and NF.  If you're curious
how to parse text using the Fortress libraries, you should look here
(it's presently far more painful than we'd like).


TEST PROGRAMS
-------------

The directory ProjectFortress/tests/ contains some Fortress programs
to test the interpreter.  Test programs that are supposed to fail
(for example, storing a String into a ZZ32-typed mutable) have names
that are prefixed with XXX.

The directory ProjectFortress/static_tests/ contains some Fortress
programs to test the static end.  Test programs that are supposed to
fail have names that are prefixed with XXX.  Test programs that are
supposed to pass static disambiguation then fail have names that
are prefixed with DXX.

The directory ProjectFortress/parser_tests/ contains some Fortress
programs to test the parser.  Test programs that are supposed to
fail to be parsed have names that are prefixed with XXX.

The directory ProjectFortress/not_passing_yet/ contains some Fortress
programs that should pass, but do not.  For example, if we had a test
file containing an error that should be detected, but it isn't, that
would be contained in ProjectFortress/not_passing_yet with a name
prefixed with XXX.  Test programs in this directory should pass
the parser.


COMPONENTS
----------

Fortress currently lacks a full-blown component system.  All the code
in your Fortress program should reside in API and component file pairs.
If you take a look at the Fortress programs in ProjectFortress/tests/,
ProjectFortress/demos/, or SpecData/examples, you'll see that they have
the same overall structure:


component MyComponent
  exports Executable

  ...  Your program here ...

  run():() = ...

end


LANGUAGE FEATURES THAT ARE IMPLEMENTED
--------------------------------------

* Object and trait declarations, including polymorphic traits.
  Constructor invocations must *always* provide the static arguments
  explicitly.

* Overloaded functions and ordinary methods.  Top-level overloaded
  functions can be polymorphic.  Nested functions and methods must be
  monomorphic.

* Polymorphic top-level functions and methods, so long as the methods
  are not overloaded.

* Checking and inference of argument types to functions, methods, and
  operators.  These checks use the dynamic types of the arguments.
  Return types are NOT checked.  Inference of static parameters is not
  complete yet; it is often necessary to provide static arguments
  explicitly.  It is *always* necessary to do so in a constructor call
  and in any situation where a static parameter occurs only in the result
  and not in the arguments to a function.  For example, you must always
  provide the array element type E and size n when invoking the
  factory array1[\E,n\]().

* Arrays of up to three dimensions.  Note that there isn't yet a
  single overarching Array type.  For more details on the array types
  and operations defined see below.  In particular, note that array
  comprehensions are not yet implemented; the array types provide
  functions to work around this lack.  Another caveat: due to a bug we
  haven't fully understood, some (but not all) uses of the compact
  notation T[n,m] for an array type cause the interpreter to fail.
  Desugaring the code by hand to e.g. Array2[\T,0,n,0,m\] works around
  this bug.

* Array aggregates except singleton arrays.

* Parallel tupling and argument evaluation.

* Parallel for loops over simple ranges such as 0#n.

* Sequential for loops over simple ranges.  The functional method seq()
  and the equivalent function sequential() can be used to turn any
  Generator into a SequentialGenerator.

* While loops, typecase, if, etc.  Note that for parametric types
  typecase isn't nearly as useful as you might think, since it cannot
  bind type variables; we are working to address this shortcoming.

* The "atomic" construct uses code based on the DSTM2 library.  Nested
  transactions are flattened.  We use their obstruction free algorithm
  with a simple lowest-thread-wins contention manager.  Reduction
  variables in for loops are not yet implemented, so perform an
  explicit atomic update or just use a reduction expression instead.

* throw and catch expressions.

* Generators.

* at expressions.

* spawn

* also (multiple parallel blocks)


LANGUAGE FEATURES THAT ARE NOT IMPLEMENTED
------------------------------------------

* Numerals with radix specifiers (which implies that some numerals may be
  recognized as identifiers)

* Unicode names

* Dimensions and units

* Static arguments: nat (using minus), int, bool, dimension, and unit

* Modifiers

* Keyword arguments

* Where clauses

* Coercion

* Constraint solving for nat parameters

* Reduction variables

* Distributions

* Any of the types which classify operator properties

* Any of the bits and storage types

* Non-RR64 floats

* Integers other than ZZ32 and ZZ64

* Use of ZZ64 for indexing (the JVM uses 32-bit indices)


CHANGES SINCE FORTRESS LANGUAGE SPECIFICATION v.1.0 BETA
--------------------------------------------------------

* Fortress 1.0 is the first  release of the Fortress language
interpreter is the first to be released in tandem with the language
specification, available as open source and online at:

    http://projectfortress.sun.com

Each example in the specification is automatically generated from
a corresponding working Fortress program which is run by every test run
of the interpreter.

* To synchronize the specification with the implementation, it was
necessary to temporarily drop the following features from the specification:

 - Static checks (including static overloading checks)
 - Static type inference
 - Qualified names (including aliases of imported APIs)
 - Getters and setters
 - Array comprehensions
 - Keyword parameters and keyword expressions
 - Most modifiers
 - Dimensions and units
 - Type aliases
 - Where clauses
 - Coercions
 - Distributions
 - Parallel nested transactions
 - Abstract function declarations
 - Tests and properties
 - Syntactic abstraction

* Libraries have significantly changed.

* Syntax and semantics of the following features have changed:
 - Tuple and functional arguments
 - Operator rules: associativity, precedence, fixity, and juxtaposition
 - Operator declaration
 - Extremum expression
 - Import statement
 - Multiple variable declaration
 - Typecase expression

* The following features have been added to the language:
 - "native" modifier
 - Operator associativity
 - Explicit static arguments to big operator applications

* The following features have been eliminated from the language:
 - Identifier parameters
 - Explicit self parameters of dotted methods
 - Empty extends clauses
 - Local operator declarations
 - Shorthands for Set, List, and Map types
 - Tuple type encompassing all tuple types

* Significantly more examples have been added.


THE DEFAULT LIBRARIES
---------------------

The components ProjectFortress/LibraryBuiltin/FortressBuiltin.fsi,
ProjectFortress/LibraryBiltin/NativeSimpleTypes.fss and
Library/FortressLibrary.fss are imported implicitly whenever any
Fortress program is run.


BUILT-IN TYPES
--------------

There are a bunch of types that are defined internally by the Fortress
interpreter.  With the exception of Any, these cannot be overridden.
The built-in types are found in
ProjectFortress/LibraryBuiltin/FortressBuiltin.fsi and
NativeSimpleTypes.fsi; documentation for the released version of these
libraries can be found in the accompanying specification release.
Most built-in types do not have any methods.  Note that the types
found in FortressBuiltin do not have methods.

Tuple and arrow types are always built in, and cannot be overridden in
any way.

Note that there isn't (yet) a trait Object!  Eventually user-written
trait and object declarations will extend Object by default; right now,
they instead extend Any by default.  We plan to migrate to a new
infrastructure for primitive objects (based on the one used for
Boolean in NativeSimpleTypes) at which point we will remedy this
situation.

Meanwhile, operations on the primitive types in FortressBuiltin can be
found in Library/FortressLibrary.fsi; again these primitive are
documented in the specification as well.  Note in particular that in
the absence of coercion, you may occasionally need to make use of widen
and narrow to convert between ZZ32 and ZZ64.


LIBRARY HIGH POINTS
-------------------

Your best guide to library functionality is the library code itself;
this can be found in Library/ and in ProjectFortress/LibraryBuiltin.
The APIs for these libraries can also be found in the language
specification (note, though, that if you downloaded the latest version
of the Fortress implementation then the two may differ).  This section
provides an overview of things you may not immediately realize are
there.

Juxtaposition of strings means string append.  You may also
find the BIG STRING operation (that concatenates strings) useful.

Several functions attempt to convert data of type Any to a string.
These include print(), println(), assert(), and juxtaposition of Any
with a string.  Right now, the FortressBuiltin types are printed using
internal magic, and object types are printed using the toString
method.  The consequence of this is that you will see a runtime error
if you attempt to print an object without first defining a toString
method.

In the absence of array comprehensions, there are several ways to
create and initialize an array (in these examples a 1-D array, but the
2- and 3-D arrays work the same way):

The simplest is to use an aggregate expression (this seems to fail at
top level in your program, which is a known bug):
    z : ZZ32[3] = [1 2 3]

If you know the size statically (it is a static parameter to your
function, or is fixed at compile time):

    a : T[size] = array1[\T,size\]()  (* lower bound 0 *)
    a[i] := f(i),  i <- a.bounds()

or:
    a : T[size] = array1[\T,size\](initialValue)

or:
    a : T[size] = array1[\T,size\](fn (index:ZZ32) => ...)

If you are computing the size at run time:
    a = array[\T\](size)
    a[i] := f(i),  i <- a.bounds()

or:
    a = array[\T\](size).fill(initialValue)

or:
    a = array[\T\](size).fill(fn (index:ZZ32) => ...)

At the moment, to create a non-0-indexed array you need to create a
correctly-sized 0-indexed array as described above, then use the
shift(newlower) method to shift the lower index.  Thus, to create an
nxn 1-indexed array you can do something like this:

    a = array2[\T,n,n\]().shift(1,1)

The replicate[\T\]() method on arrays is a little unintuitive at
first.  It creates a fresh array whose element type is T but whose
bounds are the same as the bounds of the array being replicated.  When
data distribution is fully implemented, it should respect that as well.
It is a bit like saying array[\T\](a.bounds().upper()) for 0-indexed
arrays but is slightly more graceful and deals well with non-0-indexed
arrays.

You can convert any array to use 0 indexing simply by indexing it with
an empty range:
    a[:] or a[#]  ==>  a, only 0-indexed.

Any operation that yields a subarray of an underlying array shares
structure.  If you want a fresh copy of the data, use the copy() method.

To assign the contents of array a to array b, you can use:

    a.assign(b)

if a is freshly allocated.  The following should work all the time:

    a[:] := b[:]

Right now type-level ranges don't really exist, so if you want to
operate on subarrays with statically type-checked bounds, you'll need
to work with the subarray method:

    subarray[\nat b, nat s, nat o\]():Array1[\T, b, s\]

This returns a structure-sharing subarray with base b and size s
starting from offset o in the current array.

The special factory functions vector and matrix are restricted to numeric
argument types and static dimensionality:

    x' : ZZ64[1000] = vector[\ZZ64,1000\](17)

At the moment, any Array1 or Array2 whose element type extends Number
is considered to be a valid vector or matrix respectively (this will
eventually be accomplished by coercion, and vectors will be a distinct
type).  Note that the t() method on matrices is transposition, and
will eventually be replaced by opr ()^T.


GENERATORS, REDUCTIONS, and COMPREHENSIONS
------------------------------------------

Defining new generators is discussed in detail in the Fortress
language specification, but if you're trying it yourself for the first
time, you may find it instructive to browse the source code of the libraries.


DEFINING NEW PRIMITIVE FUNCTIONS
--------------------------------

It is relatively easy to add new primitive functions to Fortress.  To
do this, you simply invoke the builtinPrimitive function with the name
of a loadable Java class which extends glue.NativeApp.  Useful
subclasses are NativeFn1 and NativeFn2, and any of the classes in
glue.prim (particularly the classes in glue.prim.Util).  Here's a
sample native binding, which defines the floor operator which returns
an integer:

    opr |\a:RR64/|:ZZ64 = builtinPrimitive("glue.prim.Float$IFloor")

You should *not* mention the type parameter to builtinPrimitive when
invoking it; doing so will confuse the interpreter.  Note also that
the interpreter requires that you declare appropriate argument and
return types for your native functions as shown above.  If you give an
incorrect type declaration on the Fortress side, you'll get
non-user-friendly error messages when the Java code is run.


DEFINING NEW PRIMITIVE CLASSES
------------------------------

To define a new primitive class, you will need to write a native
component.  Examples of these can be found in Library; anything that
starts with "native component" is a native component.  Here's the
first few lines of File.fss:

native component File
import FileSupport.{...}
export File

private language="java"
private package="com.sun.fortress.interpreter.glue.prim"

object FileReadStream(filename:String)
        extends { ReadStream, FileStream}
    getter fileName():String =
      builtinPrimitive(
        "com.sun.fortress.interpreter.glue.prim.FileReadStream$fileName")
    ....


Note that we import a non-native component that defines traits
mentioned in the extends clause.  The first two bindings must be
language and package in that order; right now only language="java" is
supported, and the package is where the backing class will be found.
In com.sun.fortress.interpreter.glue.prim.FileReadStream defines the
corresponding backing data type.  Note that FileReadStream extends
Constructor, and defines an inner class that extends FOrdinaryObject
that represents the actual values that get passed around at run time.

The methods must extend NativeMethod, but are otherwise referenced
using builtinPrimitive just as for top-level functions.

A native class can contain a mix of native and non-native method
code.  Note, however, that the namespace in which a native object is
defined is slightly odd from the perspective of library name
visibility.  For this reason, some primitive classes extend a parent
trait (defined in a non-native component) that contains most of their
non-native functionality and that has full access to the libraries.
For example, FileStream provides a number of generator definitions
that are inherited by FileReadStream.