6. File naming conventions

6.1. Suffixes

In Larceny, file names generally follow Unix conventions, even on Windows. The following suffixes have special meanings to some components of Larceny.

.sld
is the preferred suffix for files that contain libraries defined by the R7RS define-library syntax.
.sls
is the preferred suffix for files that contain libraries defined by the R6RS library syntax.
.sps
is the preferred suffix for files that contain R7RS/R6RS top-level programs (which consist of an import declaration followed by definitions and expressions).
.scm
is the preferred suffix for files that contain R7RS/R5RS definitions and expressions but don't contain any import declarations and don't define any R7RS/R6RS libraries.
.sch
is an alternative to .scm used by Larceny developers.
.slfasl
is the suffix for files that contain the compiled form of a .sld, .sls, or .sps file.
.fasl
is the suffix for files that contain the compiled form of R5RS source code (usually .scm or .sch).
.mal
is the preferred suffix for files that contain MacScheme assembly language in symbolic form.
.lap
is the suffix for files that contain MacScheme assembly language.
.lop
is the suffix for files that contain machine code segments in the form expected by Larceny's heap linker.
.heap
is the suffix for files that contain an executable heap image (must be combined with the larceny.bin runtime).

Note

In Larceny, R7RS define-library and R6RS library syntaxes are mostly interchangeable. The define-library syntax is more versatile because of its include and cond-expand features, and because it allows the name of the library being defined to contain exact integers as well as identifiers. For new code, we recommend the R7RS define-library syntax.

Note

Although the R7RS define-library syntax allows export and import declarations to be placed anywhere at the top level of the syntax, it is standard practice to use only one export declaration per library, placed immediately following the name of the library, and to use only one import declaration per library, placed immediately following the export declaration.

Warning

Some of Larceny's compilation tools rely upon the convention described within the note above, and may not work if that convention is not followed.

Tip

An R7RS library definition may be split into two or more files, with the primary .sld file containing one or more include declarations that include .scm files. If foo.sld is the primary file, then the included file is ordinarily named foo.body.scm and placed within the same directory as foo.sld. If more than one .scm file is included, we recommend foo.body1.scm, foo.body2.scm, and so on. A Larceny-specific version of foo.body2.scm that's conditionally included using the cond-expand feature might be named foo.body2.larceny.scm.

Tip

Portable source code can be tailored to Larceny and other implementations of the R7RS by combining implementation-specific mechanisms such as Larceny's -path option with the include and cond-expand features of R7RS libraries.

6.2. Directories

Larceny's root directory should contain the following files:

    larceny
    scheme-script
    larceny.bin
    larceny.heap
    startup.sch

The following subdirectories are also essential for correct operation of some features of some modes in some varieties of Larceny:

    include
    lib
    lib/Base
    lib/Debugger
    lib/Ffi
    lib/MzScheme
    lib/R6RS
    lib/SRFI
    lib/Standard
    lib/TeachPacks

The include subdirectory is used when compiling files with Petit Larceny.

The startup.sch file tells Larceny's require procedure to search some of the lib subdirectories for libraries that are loaded dynamically.

6.3. Resolving references to libraries

The R7RS and R6RS standards do not specify any mapping from library names to files or other locations at which the code for a library might be found.

R6RS non-normative appendix E emphasizes the arbitrariness of such mappings:

 

Implementations may take radically different approaches to storing source code for libraries, among them: files in the file system where each file contains an arbitrary number of library forms, files in the file system where each file contains exactly one library form, records in a database, and data structures in memory.

Similarly, programs and scripts may be stored in a variety of formats. Platform constraints may restrict the choices available to an implementation, which is why the report neither mandates nor recommends a specific method for storage.

Implementations may provide a means for importing libraries….

Similarly, implementations may provide a means for executing a program represented as a UTF-8 text file containing its source code….

 
 --

To put it more starkly:

Warning

Although implementations of the R6RS may "provide a means for importing libraries" or "executing a program", they don't have to.

R7RS section 5.1 urges implementations to be reasonable:

 

Implementations which store libraries in files should document the mapping from the name of a library to its location in the file system.

 
 --

Fortunately, de facto standards have been emerging. Larceny supports those de facto standards by providing these Larceny-specific mechanisms:

  1. R7RS/R6RS standard libraries may be imported. Their code is located automagically.
  2. Nonstandard libraries, such as (larceny compiler), may be placed in one of the directories searched by Larceny's autoload feature, provided those libraries are located in files that follow Larceny's standard naming conventions as described in the next section.
  3. R7RS/R6RS top-level programs may use Larceny's -path option to specify directories that contain other libraries the program may import, provided those libraries are located in files that follow Larceny's standard naming conventions as described in the next section.
  4. R7RS/R6RS top-level programs may use Larceny's LARCENY_LIBPATH environment variable to specify directories that contain other libraries the program may import, provided those libraries are located in files that follow Larceny's standard naming conventions as described in the next section.
  5. R7RS/R6RS top-level programs and Scheme scripts may define their own libraries in the same file that contains the top-level program or Scheme script.

R7RS programs may use any of those five mechanisms, and may also use a sixth mechanism: An R7RS program can be written as a little configuration program that loads the program's libraries from files before any libraries are imported. This sixth mechanism appears to be portable, but is not available to R6RS programs executing in Larceny's R6RS mode because it mixes execution with macro expansion, which is explicitly forbidden by one of the R6RS standard's "absolute requirements".

6.4. Mapping library names to files (R7RS/R6RS)

Suppose Larceny's -path option is used to specify a certain directory, and the program imports a nonstandard library whose name is of the form (name1 name2lastname). Larceny will search for that library in the following files:

  • directory/name1/name2/…/lastname.larceny.slfasl
  • directory/name1/name2/…/lastname.larceny.sld
  • directory/name1/name2/…/lastname.larceny.sls
  • directory/name1/name2/…/lastname.slfasl
  • directory/name1/name2/…/lastname.sld
  • directory/name1/name2/…/lastname.sls
  • directory/name1/name2.larceny.slfasl
  • directory/name1/name2.larceny.sld
  • directory/name1/name2.larceny.sls
  • directory/name1/name2.slfasl
  • directory/name1/name2.sld
  • directory/name1/name2.sls
  • directory/name1.larceny.slfasl
  • directory/name1.larceny.sld
  • directory/name1.larceny.sls
  • directory/name1.slfasl
  • directory/name1.sld
  • directory/name1.sls

The search starts with the first of those file names, continues with the following file names in order, and ends when a file with one of those names is found. The imported library must be one of the libraries defined within the first file found by this search, since the search is not continued after that first file is found (except as noted in the next paragraph).

If the search ends by finding a file whose name ends with .slfasl, then Larceny checks to see whether there is a file in the same directory with the same root name but ending with .sld or .sls instead of .slfasl. If the .sld or .sls file has been modified since the .slfasl file was last modified, then a warning is printed and the .sld or .sls file is loaded instead of the .slfasl file. Otherwise the .slfasl file is loaded.

Note

The R6RS allows arbitrary mappings from library names to library code. Larceny takes advantage of this by ignoring version numbers when mapping library names to files, and by (virtually) rewriting any version number that may be specified in the definition of a library so it matches any version specification that appears within the import form. Furthermore Larceny allows different versions of the same library to be imported, but Larceny's algorithm for resolving library references ensures that the different versions of a library will be identical except for their version numbers, which have no meaningful semantics. Although Larceny's treatment of versions conforms to the R6RS specification, it should be clear that version numbers serve no purpose in Larceny. Since the R6RS version feature has no usefully portable semantics and has been ignored by most implementations of the R6RS, it is deprecated.

6.5. Mapping library names to files (R5RS)

In R5RS mode, Larceny's -path option and LARCENY_LIBPATH environment variable may be used to specify directories to be searched by the require procedure, which takes a single symbol libname as its argument. The require procedure will search for the following files in every directory that is part of the current require path, starting with the directories specified by LARCENY_LIBPATH and the -path option:

  • libname.fasl
  • libname.sch
  • libname.scm

These files are expected to contain R5RS code, not library definitions. Otherwise the search proceeds much the same as when searching for an R7RS/R6RS library.

Note

The require path is specified by startup.sch in Larceny's root directory, but may be changed dynamically using the current-require-path parameter. Changing the require path is not recommended, however, because Larceny relies on the require path for dynamic loading of libraries used by several important features of Larceny, notably R7RS and R6RS modes.

Procedure require

(require libname)

libname must be a symbol that names an R5RS-compatible library within the current require path.

If the library has not already been loaded, then it is located and loaded. If the library is found and loaded successfully, then require returns true; otherwise an error is signalled.

If the library has already been loaded, then require returns false without loading the library a second time.

Procedure current-require-path

(current-require-path ) => stringlist

(current-require-path stringlist)

The optional argument is a list of directory names (without slashes at the end) that should be searched by require and (in R7RS/R6RS modes) by Larceny's autoload feature. Returns the list of directory names that will be searched.