Heading:
Cedar System Modelling Reference Manual
Page Numbers: Yes X: 527 Y: 10.5"
Inter-Office Memorandum
ToCedar InterestDateJanuary 17, 1982
FromEric Schmidt, Butler LampsonLocationPalo Alto
SubjectCedar System Modelling Reference ManualOrganizationCSL
XEROX
Filed on: [Indigo]<Cedar>Documentation>ModelRefMan*.Bravo and .Press
Outline
1. Introduction
2. Operational Overview
3. Simple Use of the Modeller
4. Advanced Use of the Modeller
5. Modelling Language
6. Implementation Details
7. Use from the Cedar Executive
8. How to Get Started
9. Example of Model
10. Other Modelling Tools: DesignModel
11. References
12 Appendices:
A. Criteria for Replacement
B. Current Limitations
C. Semi-Formal Syntax and Semantics
Introduction
The Cedar system modelling facilities are a complete system for maintaining and manipulating both small and large collections of Cedar modules. The Cedar programmer writes Cedar system models, which describe systems in terms of their interfaces (DEFINITIONS modules) and their implementations (PROGRAM modules). In these models, the programmer 1) specifies how his modules interconnect, 2) instructs the modeller how to compile his system, and 3) identifies files by unique version numbers. When the user first starts the modeller on a particular model, the modeller insures that those files referenced by the model are on the disk.
The modeller keeps track of source and object files and tries to automate part of the usual edit- compile- debug- edit- cycle. As the programmer makes changes, the modeller records which files have changed. When instructed by the programmer, the modeller will compile all the files the programmer has changed, and any that depend on files changed, and then will load and start the compiled object files. In many cases using the modeller for these tasks will be faster than using the Binder and conventional Loader since the modeller can replace old versions of modules with newer ones "on the fly" without re-loading all modules in a system.
This memo describes a preliminary version of the modeller. Current limitations are described in Appendix B. Please send comments on the implementation to Schmidt.PA, and comments on the design to Schmidt.PA and Lampson.PA.
Operational Overview
System models are represented as text files that conform to a syntax described in section 5. Roughly, they correspond to "decorated" .Config files containing more information than can be expressed in C/Mesa.
Programmers must create a model to begin with. Some simple models can be generated by hand, but others may be very complicated. Section 11 describes a conversion aid called DesignModel that will generate models from .Bcd files.
Given that a system model (or set of them) has been generated by hand or generated by DesignModel, a modeller can be run on this model. While being run relative to a model, the modeller follows edits to files and provides automatic compilation and loading facilities, including the ability to replace modules in an already loaded and running system. The modeller presents itself as a Tajo window (tool), whose topmost subwindow contains useful pushbuttons and fields for fill-in. The next two sections describe the functions of each pushbutton (and associated files), roughly in the order of their use.
Under certain conditions, the modeller can replace a loaded module by a new version in an already-loaded and running system. This facility, called module replacement, can avoid the uneccesary re-loading of other modules in a system and provides fast turnaround for small program changes.
Since the modeller may only model one nested set of models at a time, more that one modeller may be run concurrently as long as they model disjoint sets of models. Complete information about this and module replacement is found in section 4.
Details about the implementation of certain loading and parameterization problems (present in the system for historical reasons) are discussed in section 6, along with information about an internal data base.
The modeller window can be controlled from a command file as well as from pushbuttons. This is discussed in section 7.
This memo concludes with a list of limitations in the current, unfinished version of the modeller and an extended example. References (e.g. [FastTurnaround1]) are listed at the end of this document.
Simple Use of the Modeller
StartModelling!
When started, the modeller will display a Tajo tool window as shown in Figure 1. Before any of its features can be used, the modeller must be given a model file (hereafter called the current model). The name of the current model is entered following FileName: on the first line of the window. Push the StartModelling! button to begin modelling the current model.
StartModelling! will force the modeller to initialize itself and prepare to track changes to files in the model. To do this, it will read in the current model and analyze the model as follows:
1) Each file involved in the model is described by a remote host and directory where the file may be found, and a unique identifying number. (Currently the file’s creation date.) If the current model refers to a source file that is not on the local disk the modeller retrieves this source file to the local disk. If a copy is on the local disk already, StartModelling! does not retrieve the remote version even if the create dates of the local copy and the date in the model do not agree. It will also retrieve a similarly named .Bcd file from the same directory, if one is not on the disk..
2) It scans all the sources and fills in any defaults left unspecified in the current model.
3) It checks the parameters to the source files for accuracy.
Notice Operation
After the StartModelling! command completes, the modeller is ready to track changes to files listed in the current model. The Tajo editor (by default) will be connected automatically to the modeller so that, whenever a Store or Save command is given to the editor, the modeller will be notified. If the file is listed as part of the current model, the modeller will perform a notice operation on the newer version of the file by adjusting its internal tables accordingly. To do this, the modeller will analyze the new version to see if any of its DEFINITIONS, etc. have changed. At this point the model file on the local disk refer to older versions of these files. (The changes to the model may be too extensive for the modeller, and the model may need to be hand edited.)
CompileWithOutRepl!
After changes have been made the modeller will compile modules that have been edited and then will compile any files that depend on those that were edited, and so on until all files that need to be compiled or recompiled have been. (Should there be compilation errors, further edits should be made, and CompileWithOutRepl! should be pushed again.)
The modeller will ask before confirmation before compiling a module. Typing ’y’ or CR in answer to the question will proceed with the compilation, typing ’n’ will skip this compilation and proceed to others, and typing ’q’ will quit the compilation phase immediately.
The modeller will "guess" a plausible .Bcd filename for each source file mentioned in the model and look for such a file. If it finds one, it checks the .Bcd to make sure it came from the source file the modeller has, and was compiled with the same compiler switches and TYPEs in its DIRECTORY statement. Eventually this information will be kept in a Cedar database.
Before compiling anything the modeller will store a new version of the model on the local disk. This new model will refer to the latest versions of files that have been noticed by the modeller.
LoadAll!
The modeller is able to run object files produced by the compiler. This must be done in two steps (1) loading the .Bcd files into memory, and (2) STARTing the CONTROL modules. When LoadAll! is pushed, the .Bcd modules for the files listed in the current model are loaded and all references between modules are resolved.
StartAll!
Once loaded, any CONTROL modules (in the current model, see below) may be STARTed by pushing the StartAll! button. StartAll! can be pushed once per completed LoadAll!, and starts only those modules loaded by the last LoadAll!
UnLoadAll!
The loaded modules may be unloaded and resources reclaimed by pushing UnLoadAll!. Once this has been done, any reference to the formerly loaded programs will almost certainly result in an AddressFault or StackError, since the global frames and code segment spaces have been invalidated.
StopModelling!
Pushing StopModelling! terminates the modelling on the current model. The modeller will offer to write out a new version of the model it is current on if recent edits have notified the modeller of new versions of files in the model. StopModelling! should be preceded byUnLoadAll!. If UnLoadAll! is not given, the loaded bcds remain loaded, and may not be unloaded after the StopModelling! button is pushed. StopModelling! may be followed by StartModelling! on another model.
Other Modeller PushButtons
AttachEditor:
CompileWithRepl!
LoadWithRepl!
MakeModel!
SetWorkingModel!
These are described in the next section, "Advanced Uses of the Modeller."
Permanent!
CompileWithOutRepl! does not copy changed files out to the remote servers, so some of the filenames in the current model will refer to local, not remote, files. When you want those files transferred, push the Permanent! button to store the new versions on the remote server(s).
Temporary!
To force the modeller to save the model you’ve been current on, but not to transfer files to remote servers, push the Temporary! button. This command acts like a checkpoint command and will produce a new version of the model, annotated to show any new versions of files only on the local disk. This is primarily intended for protection against crashes of Cedar or the modeller.
Notice!
If you need to include new files that were not created under the modeller’s control, such as new versions of system files, you may explicitely invoke the Notice processing by inserting the name of the file to be noticed after FileName: on the Notice! line, and pushing Notice!. (If an extension is omitted, ".Mesa" is assumed.) The modeller will process this explicit Notice operation just like it processes those generated by the editor.
NoticeAll!
NoticeAll! can be used to let the modeller look for any new versions of files referred to in the model and do an automatic notice operation on them. This should be used with care, in case standard system files have been edited by mistake.
Type (w/o defaults)!, Type (w/defaults)!
The modeller keeps an internal description of the current model, which may differ from the model file if notice operations have been performed. Pushing either Type...! button will print the internal copy of the model.
Confirm: {TRUE, FALSE}
CompileWithOutRepl! (or CompileWithRepl!) normally pauses to ask the user to confirm the compilation of a file. This gives the user control over the modeller. If FALSE is selected, then the modeller will compile files without pausing for confirmation.
Deactivate!
Deactivate! will make the modeller tool inactive and remove the tool window from the display.
In a typical session, you’d start with the StartModelling! command, make a few edits, and then give the CompileWithOutRepl! command to generate the new model and compile everything. You could then go ahead and make more changes, push CompileWithOutRepl! again, and so forth. Whenever the files are worth saving on remote file servers, you’ll push the Permanent! button. Finally, push StopModelling! to shut down the modeller.
You should not invoke the Compiler or Binder directly during this session. If you do, you’ll need to StartModelling! again since you may interfere with the modeller’s cache of information.
The modeller could compile programs in the background, but this could result in a great deal of erroneous re-compilation if you were changing sets of interdependent modules.
Advanced Use of the modeller
Module Replacement (CompileWithRepl!, LoadWithRepl!)
Programmers may want to make a minor change to an already loaded and running system. When the modeller is used in replacement mode, modules may be replaced without losing any global state and without unnecessary reloading, subject to certain restrictions. (See [FastTurnaround1] and [FastTurnaround2] for more information.)
For example, suppose TreeImpl.Bcd has been loaded as a part of Parser.Model, and the model has been started. Suppose TreeImpl.Mesa (the source for TreeImpl.Bcd) has an erroneous statement "X←1;" that should be "X←2;", and X is declared local to some procedure in TreeImpl.Mesa. To make change this statement without reloading the entire system, the programmer would proceed as follows:
1) The programmer edits TreeImpl, alters the assignment statement, and saves the new version. The modeller then notices the new version.
2) The user then pushes CompileWithRepl!, which is identical to CompileWithOutRepl!, except the compiler is invoked with instructions to check that TreeImpl.Bcd is replaceable. The compiler is given information about the old version of TreeImpl.Bcd to make this check. If there is no older version, CompileWithRepl! and CompilerWithOutRepl! are equivalent..
3) If the compiler reports that the module is replaceable, the user may push LoadWithRepl! to replace old code for TreeImpl with the new code containing the corrected "X←2;" instruction. TreeImpl will not be STARTed a second time and initialization of global variables in TreeImpl will not be repeated.
In general, the modeller and compiler will try to replace any module which is compiled and loaded in replacement mode (i.e., with CompileWithRepl! and LoadWithRepl!) Refer to Appendix A, "Criterion for Replacement," for a summary of (current) limitations of module replacement.
The old .Bcd file remains loaded until there is a successful compilation in replacement mode, and the new version is replaceable. The modeller may need to rename the old .Bcd: If there are errors compiling the new version and no new .Bcd is produced, the old .Bcd is not renamed by the modeller. If the compilation succeeds then the old .Bcd will be renamed, regardless of replaceability (by appending a digit, e.g. TreeImpl1.Bcd). Therefore, pushing LoadWithRepl! will load the new .Bcd if it is replaceable, and UnLoadAll! followed by LoadAll! will always load the new .Bcd, along with all the other modules in the current model.
Nested Models
Models may refer to other models (for syntax, see Language section). These nested models define a tree of models with the model given to StartModelling! as its root. The editor notice operation, Notice!, and NoticeAll! buttons apply to all files in all the models in this tree. Other commands (such as Compile...!, Load...!, and Type..!) are model-specific, and use the current working model, which may be set by inserting the model file name after FileName: on the SetWorkingModel! line and pushing SetWorkingModel! The default working model is the root model and the working model can be reset to the root model by entering the null string after FileName: and pushing SetWorkingModel!
MakeModel!
MakeModel! takes a model you supply and tries to produce on the local disk a set of .Bcd files ready to be loaded and run. MakeModel! will do whatever is necessary to make the model. If there is a .Bcd already available for the model, it will simply retrieve the .Bcd file. If it has to recompile any files, it will do the minimum necessary. MakeModel! is similar to a sequence of StartModelling! and CompileWithoutRepl! with one exception: If the model describes a file on a remote server with a different create time than the create date of the file on the local disk, the remote version is retrieved, deleting the other version on the local disk. No confirmation is requested. Use carefully. MakeModel! may be followed by other modeller commands, e.g. LoadAll! or StopModelling!
AttachEditor: {TRUE, FALSE}
When it is started, the modeller arranges to be called when the user saves or stores a file using the Tajo editor. More than one modeller may be started, in which case (for implementation reasons) only one can be attached to the editor at a time. If for this, or any other reason, you do not want the editor to notify the modeller of such changes, select FALSE for this field in the modeller window.
The Modelling Language
Philosophy:
The reader should be familiar with these definitions before proceeding:
module
One per file, there are two kinds: definitions and implementation.
interface:
Informally used for definitions modules.
module name:
Each module has one or more module names.
interface type:
An specific version of a definitions module defining the names and types of procedures, etc. declared in the definitions module. An interface type does not specify any values for the objects it define, so no association between procedure declarations in definitions modules and their code is possible. Standing alone, a .Bcd for a definitions file is an interface type.
interface instance or record:
A record containing values of items declared in an interface type, such as pointers to the code for procedures, etc. Some implementation module has to provide these values.
imports and exports:
An interface instance is created by an implementation module EXPORTing the interface. The procedures, etc. exported by the implementor can be used when another module IMPORTs the interface. (Actually, it imports the interface record.)
To understand the Modelling language, the reader must first understand some features of the Mesa language. Most Mesa modules (Definitions and Program) have a DIRECTORY statement which defines at compile time which Definitions modules will be available for declarations, etc. If the client of a Definitions module listed in the DIRECTORY statement wants to invoke a procedure defined in the Definitions module it must also IMPORT an instance of that Definitions module. (It actually imports an interface record, which usually contains pointers to procedure bodies in other modules.) These instances must in turn be EXPORTed by some other, implementing, Program module. The correspondence between exporters and importers is usually set up by the Binder, not the Compiler. In what follows, we merge the information about which interfaces to use (i.e. which Definitions files to use) and which instances of those interfaces to use (i.e. which instances to import). We will think of a Definitions file as defining a TYPE, much in the same way as a RECORD declaration. In the Modelling language you can declare a variable Foo of type TYPE (i.e. an interface type), and then declare a variable FooImpl of type Foo (FooImpl is an interface record). We can give FooImpl a value from a module that exports Foo.
The modelling language is similar to Mesa and replaces the Binder’s C/Mesa language. An applicative language, it has no assignment operator, so bindings are similar to procedure calls.
Small Model Example:
StreamT: TYPE Stream == @[Indigo]<Cedar>StreamDefs.Mesa!223456;
FileAndStream: PROC[StreamInst: StreamT] RETURNS[CommonInst, FileInstance] [
Common: TYPE == @[Indigo]<Cedar>CommonDefs.Mesa!654322;
CommonInst: Common == @[Indigo]<Cedar>CommonImpl.Mesa!224536[Common];
FileT: TYPE File == @[Indigo]<Cedar>FileDefs.Mesa[Common];
FileInstance: FileT == @[Indigo]<Cedar>FileImpl.Mesa[FileT, StreamT, StreamInst]
]
The Language:
A model is a list of expressions. One of the expressions should be the declaration of a procedure (PROC) which contains the implementing modules. Any other expressions are treated as global and serve to define commonly needed interfaces. This procedure takes parameters and returns results. These parameters are usually instances of the Pilot runtime environment, but may also be strings (e.g. compiler switches and host names, etc.) This procedure can return any value passed in or declared in the body of the procedure. The language obeys normal scoping rules and PROCs can be nested inside other PROCs, etc. There should be one outermost procedure, however. Just like C/Mesa’s nested configurations.
In the example model, each line is an expression that defines a variable in the modelling language. The outermost (and only) PROC in the example is named "FileAndStream."
TYPE declarations:
Each variable in the modelling language has a type. Types can be conventional, e.g. a variable may have type STRING or PROC, as in Cedar, or specific to modelling, e.g. a variable may have type "TYPE Mod", where Mod is a module name. In the modelling language, a variable of type TYPE Mod can be given a value (by "==") that is a definitions module with "Mod" as a module name.
In the example,
StreamT: TYPE Stream == @[Indigo]<Cedar>StreamDefs.Mesa!223456;
defines a variable "StreamT", whose type is "TYPE Stream" and whose value is the definitions file StreamDefs.Mesa. "StreamT" obeys normal scoping rules and is subsequently used in the model to provide this interface to every module that needs it. The host and directory after the @-sign give a hint as to the file’s location, and the decimal number following the ’!’ is the files create-date which serves to uniquely identify it. The file location is a hint since ANY file with the same unique-id is acceptible, although in practice the modeller will only look on the local disk and the location listed in the model for this file. (It is conceivable these creation dates may not be unique, but they’re the most-unique identifiers we have at the moment. We are working on a better scheme.)
When the variable name and module name are equal, the name after TYPE can be omitted.
Common: TYPE == @[Indigo]<Cedar>CommonDefs.Mesa!654322;
defines a variable "Common" in the model whose type is "TYPE Common", and whose value is that version of CommonDefs.Mesa. It is important to remember that Common is not a variable of type TYPE, it is a variable of type "TYPE Common", a more restrictive set of values. (In the modelling langauge, no variable can have type "TYPE", they all have type "TYPE Mod" for various module names "Mod.")
Instance declarations:
An instance expression defines one or more instances of interfaces, which the program modules import and export. These expressions take parameters which define 1) which interface types to use when compiling, and 2) which interface records to pass to the module as its IMPORTS (i.e. what the Binder does now.) For example, a module CommonImpl.Mesa that exports an instance of the interface Common, imports nothing, and had one DIRECTORY entry which was an interface named "Common" could be expressed as
CommonInst: Common == @[Indigo]<Cedar>CommonImpl.Mesa!224536[Common];
This expression defines CommonInst, a variable in the modelling language, to be of type Common. The value of this variable is an interface instance (or interface record), exported by the file "CommonImpl.Mesa," which itself has one DIRECTORY statement entry for Common.
Program modules also have to import instances of various interfaces. The required instances can be specified as parameters to the program module just as the TYPEs are. For example, a program module in the file FileImpl.Mesa, which imported an instance of Stream and exported an instance of File, would have as parameters both TYPEs (i.e. both Definitions files to use) and also an instance of Stream, named StreamInst in the example. So
FileT: TYPE File == @[Indigo]<Cedar>FileDefs.Mesa[Common];
FileInstance: FileT == @[Indigo]<Cedar>FileImpl.Mesa[FileT, StreamT, StreamInst]
defines an instance of an interface of type FileT, exported by FileImpl.Mesa.
In the example, StreamInst is not given a value in the model. However, it is declared in the parameter list for FileAndStream and will be given a value (from outside this model, e.g. the Pilot load state) when the model is loaded.
Parameters:
The order of parameters is not significant. Modules may take two kinds of parameters: TYPE and instance variables. The modeller matches up values on the parameter list (actuals) with the corresponding formal, according to these rules:
In a Mesa file, a Directory statement like
DIRECTORY
Stream;
is an abbreviation for
DIRECTORY
Stream:
TYPE Stream;
where the Stream on the left is the name of the interface in the Mesa source file, and it can be matched with any Definitions file (on the local disk) with module name "Stream" (indicated by "Stream" after TYPE). More generally,
DIRECTORY
Defs:
TYPE Mod;
requires that whichever Definitions file is matched with Defs have module name "Mod." (See [Compiler1] for more documentation on the TYPE construct in Directory statements.) When analysing a source file with such a Directory statement, the modeller matches any parameter with type "TYPE Mod" to the corresponding entry "Defs" in the Directory statement. (In the example, any parameter with type TYPE Stream will match Stream in the Directory statement.).
The FROM clause allowed in Directory statements is ignored. Therefore.
DIRECTORY
Stream:
FROM "somefile.bcd";
is treated by the modeller as if it were
DIRECTORY
Stream:
TYPE Stream;
In Mesa files, an IMPORTS statement like
IMPORTS Stream =
is an abbreviation for
IMPORTS Stream: Stream =
The general case is IMPORTS Name: Defs, where Name is the name used to reference procedures, etc. defined in the Definitions file connected to "Defs", defined in the modules Directory statement. In the modelling language, "IMPORTS Name: Defs" is matched to any modeller variable with whichever type was matched to "Defs." That is, the interface instance variable has the same type as that matched with the Directory entry for "Defs."
Keyword Notation:
When two parameters have the same type (e.g. two definitions files with the same module name or two interface records from the same interface) keyword notation must be used to disambiguate the references. For Directory entries
DIRECTORY
Defs1: TYPE Mod,
Defs2:
TYPE Mod;
the model will have to specify which type variable to match with Defs1 and Defs2 using keyword notation, such as
== @ParserImpl.Mesa[Defs1: File1, Defs2: File2];
in the parameter list after the file listed in the model, where File1 and File2 have type "TYPE Mod."
For Imports,
IMPORTS Instance1: Defs, Instance2: Defs =
the model will have to specify which interface to match in the parameter list, e.g.
== @ScannerImpl.Mesa[Defs: Stream, Instance1: Actual1, Instance2: Actual2];
in the model, where Actual1 and Actual2 have the type matched with Defs (in the example, this is Stream).
LET clauses:
Some modules may export more than one interface record. For these cases, the LET statement declares multiple variables exported by one module. For example, if YImpl.Mesa exported Y and Z, we could write
LET [YImpl: Y, ZImpl: Z] == @YImpl.Mesa[X, Y, Z, ZImpl];
to define an instance of Y as YImpl and Z as ZImpl. The elements in the LET clause may be written in any order. (In the modelling language the file following the @-sign can also be a model, in which case the LET declares variables that the model following the @-sign RETURNs).
Definitions modules with more than one module name may declare two variables, each with a different TYPE, using a LET statement. For example, if Defs.Mesa looks like
Mod1, Mod2: DEFINITIONS = { ... }.
then in the model
LET[X1: TYPE Mod1, X2: TYPE Mod2] == @Defs.Mesa;
will define two variable with the TYPEs for each of the module names Mod1 and Mod2 in "defs.mesa". Of course, if the variable names are equal to the module names then the module names after TYPE may be omitted, e.g.
LET[Mod1: TYPE, Mod2: TYPE] == @Defs.Mesa;
CONTROL modules and compiler parameters:
After files listed in the model are loaded, the user may want some of them started. (These modules are called CONTROL modules in C/Mesa.) Any (program) module which must be started by the modeller loader should define a dummy variable, of type CONTROL (it doesn’t matter what the variable’s name is as long as it is unique). For example:
LET[Odd: CONTROL, XImpl: X] == @XImpl.Mesa[X];
declares both XImpl, an instance variable of type X, and that this module should be STARTed when the user instructs the modeller to start the loaded system.
Compiler parameters (such as bounds-checking) can also be specified (as a string parameter to the program module after the @-sign). Switches don’t matter for Definitions files. If not specified, the compiler defaults are used. We consider this a kludge and are working on a better system.
.Bcd and .Config files in the model:
The Modelling philosophy stresses control over source files, since .Bcds cannot be recompiled with different parameters, etc. But it is still possible for a model to reference a particular .Bcd (e.g. "@Example.Bcd!123456"). A .Bcd’s parameters are interface records of specific types, never TYPEs. If a .Bcd of the specified type is unavailable when the modeller is run, the modeller will give some sort of error message. Likewise a .Config can be a module within a model. If necessary, the modeller will invoke the Binder on the .Config but, as in the .Bcd case, you have no flexibility with the parameters which must be of the correct type. .Bcds that are loaded as part of a nested Config are not replaceable.
PLUS and THEN operators:
The Binder has PLUS and THEN operators that merge partially-filled interface records. The modeller accepts the PLUS and THEN operators on the right-hand side of ’==’, just like those in C/Mesa. For example, if X is exported by both XImplA and XImplB, you would have to express it as
X: TYPE == @X.Mesa!2511989735[];
XImpl: X == (@XImplA.Mesa!2505871727[])
PLUS (@XImplB.Mesa!2517520325[]);
XImpl, of type X, is defined in terms of the exports of two modules that export X. The THEN operator is similar.
The current implementation of the modeller will alter the model to define auxiliary variables for each of the parenthesized expressions in the example above.
Importing and Exporting Program Modules:
Mesa programs may mention a program module name in their Directory statements and import this module name, rather that a Definitions file, giving them a POINTER to the imported module’s global frame. (This is used, for example, as a parameter to Runtime.GetTableBase[].) The modelling language handles this case by treating the module being imported as a type, and the POINTER to its global frame as an instance of that type. The type is declared normally, as well as an instance of that type, and a LET statement is used to assign the values. For example,
LET[XYZ: TYPE Mod, XYZImpl: XYZ] == @ParserImpl.Mesa;
in the modelling language defines a variable "XYZ" with a type for a pointer to the frame of a module with module name "Mod", and then declares a variable XYZImpl of type XYZ that can be imported. Such an importer will have XYZ as a parameter to match the importing module’s DIRECTORY entry, and XYZImpl to match the import.
OPEN clause and scoping
Variables defined in procedures scope just like any other Pascal- or Algol-like langauge. A variable is available within the scope it is defined and is also available in any procedure nested within its defining scope. These scopes are usually created by procedures, where the parameters to the procedure, the returned values, and variables defined in the body of the procedure are all in the procedure’s scope.
A primitive data-structuring facility is also available in the modelling language. A variable can have as type a list of other variables, which themselves have types. Each element of this list variable is referred to by qualification ala Mesa RECORDs. For example
ASystem: [
BImpl: B,
CImpl: C
];
defines a variable ASystem composed of two others: BImpl and CImpl. These two are available only by explicit qualification using a period: e.g. ASystem.BImpl, or by OPENing ASystem to make BImpl and CImpl available without qualification. For example,
OPEN ASystem;
The OPEN statement must appear before any uses of un-qualified variables.
The OPEN statement can also OPEN files to make the variables defined in the file available. For example, if SystemFile.Mesa contained
-- SystemFile.Mesa!5678
A:
TYPE == @A.Mesa!123[];
B:
TYPE == @B.Mesa!345[];
then the statement
OPEN @SystemFile.Mesa!5678;
will make A and B available in the model opening SystemFile.Mesa. Similarly a list variable could be in SystemFile.Mesa:
-- SystemFile.Mesa!5566
ASystem: [
B: TYPE == @B.Mesa!345[];
C:
TYPE == @C.Mesa!346[];
];
But then two OPENs are required to gain unqualified access to B and C: The first OPEN to read the file and make ASystem available:
OPEN @SystemFile.Mesa!5566;
Then a second OPEN to make B and C available:
OPEN ASystem;
This is most useful for including specific versions of Definitions files, such as the Pilot Runtime system.
Defaults
Defaults can be used to express some of the information in a model more compactly. In procedure parameter lists and LET clauses "*: id" is short for "idImpl: id", where "id" is a TYPE. In procedure parameter lists, "id: *" is short for "id: TYPE, idImpl: id", and "id *" stands for "id, idImpl" in module parameter lists.
":@Name[]" is the same as "Name: TYPE Name == @Name.mesa[]" if Name.mesa is a Definitions module whose module name is "Name". ":@NameImpl[]" is the same as "NameImpl: Name == @NameImpl.mesa[]" if NameImpl.mesa is a Program module that exports Name. The TYPE Name must have been defined previously.
The ":@" default can also be used when the filename does not end in .Mesa and or when the filename has more than one extension. If a sub-string of the name, separated by periods, is preceded by an asterisk, then that will be the name of the variable being defined. For example, ":@Name[]" and ":@*Name.Mesa" are identical, and ":@Cedar.*File.Parser[]" is identical to "File: TYPE File = @Cedar.File.Parser.Mesa[]". We call the sub-part of the file name preceded by an asterisk its principal part.
The ".Mesa" can be omitted from the filename, and the compiler switches need to be specified only when they differ from the Cedar/Mesa compiler defaults. Compiler defaults in a User.CM file are ignored.
Defaulting Parameters
Some or all of the parameters to a file (after @) can be omitted. If the formal appears as
DIRECTORY
Stream;
in a Mesa source file, the formal is matched up with a variable declared as "Stream: TYPE Stream ==" in the model. More generally, if the formal appears as
DIRECTORY
Var: TYPE Stream;
the formal is matched up with a variable declared as "Var: TYPE Stream ==" in the model.
Similarly for interface records,
IMPORTS Stream
in a Mesa source file is matched up with "StreamImpl: Stream ==" in the model, and
IMPORTS Instance: Stream
is matched up with "Instance: Stream ==" in the model.