Assembler Form for Astarte Abstract Machine


Stack notation

Many instructions work on the data stack or the type stack. The effect that an instruction has on the stack is shown in a before and after view of what is on the stack. In each view, the top part of the stack is shown, from top to bottom. There can be more of the stack below the part that is shown. What is shown in the after view replaces what is shown in the before view. For example, the MINUS instruction has the following stack diagram.

Data stack
 before    after  
Y** : (any numeric species) (X - Y)** : (a numeric species)
X** : (any numeric species)  

This instruction pops two numbers (first Y then X) and then pushes X - Y. Notice that X and Y were pushed in the opposite order from the order in which they are popped. First X was pushed and then Y was pushed. So you think of X as the first parameter of MINUS, and Y as the second parameter.

Items on the stack can be promises. The MINUS instruction needs to evaluate any promises so that it can perform the subtraction. The * indicates this evaluation. See forcing evaluation for the meaning of evaluation marks.


Declarations: Labels and names

@LABEL n

A label declaration provides a way to refer to the thing declared in the declaration that immediately follows the label. Each label declaration gives a number that indicates the label number. Labels created in label declarations are called global labels.

When a global label is written in an assembler program, you have the option of preceding the label number by a > sign. For example, you can write

    @LABEL >20
  

Binary form

@ID name

The program uses names for items by declaring them in an declarations just after a label instruction, and thereafter referring to them by the label. For example,

   @LABEL     1
   @ID        kangaroo
  
indicates that label 1 refers to name kangaroo. An @ID declaration is only used to define an identifier that will be used to refer to a data item.

Example.

Binary form

@NAME name

A @NAME declaration is similar to a @ID declaration, but is used to create a name that refers to something other than a data item.

Binary form


Declarations: Defining constants

@STRING "str"

A string declaration produces a string constant, which can contain any characters, as well as the escape sequences \n (newline), \t (tab), \r (carriage return), \\ (backslash), \" (quote) and \{n} (character code n) where n is a decimal integer. The string is written inside double-quote marks. It can begin either on the same line as @STRING or on the next line, and can continue for any number of lines. (A line break inside the string is part of the string.)

The species of the thing pushed is List(Char) (a list of characters).

Typically a @STRING declaration is preceded by a label, and the string is referred to by that label.

Examples:

    @LABEL 1
    @STRING "you can have short strings"
    @LABEL 2
    @STRING "or you can
    have longer strings that
    span several lines and have special things
    like \t and \n or \{3}."
    @LABEL 3
    @STRING
    "another string constant"

Binary form

@INT n

Define an integer constant. The integer is written in decimal, possibly with a sign.

The species of the constant is Integer.

Typically, an @INT declaration is preceded by a label, and the integer is referred to by that label.

Examples:

    @LABEL 41
    @INT  456
    @LABEL 42
    @INT  -123456789123456789

Binary form

@REAL n

Define a real constant. The number written in decimal, possibly with a sign. There can be a decimal point, with at least one digit on each side of the decimal point. There number can end with Eexp where exp is a (signed) decimal exponent of 10. There cannot be any spaces in the number. For example,

   @LABEL 19
   @REAL 3.67E-3
defines the real constant 0.00367

The species of the constant is Real.

Typically a @REAL declaration is preceded by a label, and the number is referred to by that label.

Binary form

@RAT n

Define a rational constant. The number n is written in the same format as for a @REAL declaration.

The species of the constant is Rational.

Typically a @RAT declaration is preceded by a label, and the number is referred to by that label.

Binary form

@LIST n

Define a list constant. The number n indicates how many members the list has. After the @LIST declaration must be exactly n declarations of constants that are the members of the list. The constants can be define by @INT, @REAL, @RAT, @STRING and @LIST declarations. But all of the constants must be of the same species.

The species of the constant is List(T) where T is the species of each of the constants in the list. (When the constants are defined using INT, the species can be either List(Natural) or List(Integer).)

Typically a real declaration is preceded by a label, and the number is referred to by that label.

Example:

    @LABEL 20
    @LIST  4
    @INT   18
    @INT   22
    @INT   -5
    @INT   17
creates the list constant [18, 22, -5, 17], whose species is List(Integer).

Example

Binary form


Declarations: Making definitions and performing actions

@EXECUTE n

Evaluate an expression. The general form is as follows.

Form of @EXECUTE
@EXECUTE n Begin the global definition fetch. The number n tells an upper limit on the number of slots that are required in the static environment. That is, it tells how many definitions will be fetched. See specifying the size of the environment.
instructions These instructions fetch definitions from the global tables that this code wants to use. See building the static environment.
BEGIN-EXECUTABLE i Begin the executable part. The number i tells an upper limit on the number of slots that are required in the local environment during the evaluation. See specifying the size of the environment.
instructions These instructions are performed
END One byte

Example

Binary form

@HIDDEN-EXECUTE n

Evaluate an expression. This is exactly the same as an @EXECUTE, but it indicates that the actions performed are probably of no interest to a debugger.

@DEFINE n

Create a definition in the global tables. The general form is as follows.

Form of @DEFINE
@DEFINE L mode

This definition defines the identifier that is defined (using an @ID declaration) at label L. Mode is a string of zero or more characters, without intervening spaces, indicating how the definition is entered into the table. The possible characters are as follows. (The case does not matter. You can use either lower case or upper case letter here.)

 o  Override a prior definition. The prior definition must have had mode u or d.
 u  Underride prior definitions. This definition will only be used if there is no former definition that shadows it. This mode implies mode d.
 d  This definition can be overridden later, but only by a definition with mode o.
 i  This is a definition of an irregular function
 p  Any two definitions that have mode p are allowed to conflict. The most recently installed one will have precedence.

 

type instructions This sequence of instructions is responsible for putting the polymorphic type of this definition on the top of the type stack.
BEGIN-GLOBALS n Begin a sequence of instructions that fetch definitions from the global definition table. The number n tells an upper limit on the number of slots that are required in the static environment. See specifying the size of the environment.
instructions These instructions fetch definitions from the global tables that this code wants to use. See building the static environment.
BEGIN-EXECUTABLE i Begin the executable part. The number i tells an upper limit on the number of slots that are required in the local environment during the evaluation. See specifying the size of the environment.
instructions These instructions are performed to compute the item that this definition names. They leave the value on the top of the data stack when they are done.
END One byte

Example

Binary form


Declarations: Creating new species

@BEGIN-EXTENSION

Begin an extension. All declarations that create new species, parameterized species, genera, or parameterized genera, or that indicate relationships among those things, must occur between @BEGIN-EXTENSION and @END-EXTENSION.

A species, genus, etc. cannot be used until the extension where it is created has ended.

This declaration has no parameters.

Binary form

@END-EXTENSION

End an extension.

Binary form

@NEW-SPECIES name

Define a new species called name. Typically, this declaration is preceded by a label, so that the species can be referred to by that label.

Example:

    @BEGIN-EXTENSION
    ...
    @LABEL       5
    @NEW-SPECIES Widget
    ...
    @END-EXTENSION

Example.

Binary form

@IMPORTED-SPECIES name

Refer to a species that is defined in another package, and that has already been defined via an import, or to a species that is built into the abstract machine. This declaration does not create a new species, but provides a way of referring to one that has already been defined. This declaration is typically preceded by a label.

Example:

    @BEGIN-EXTENSION
    ...
    @LABEL             5
    @IMPORTED-SPECIES  Widget
    ...
    @END-EXTENSION

Binary form

@NEW-FAMILY opts name

Create a new parameterized species called name. Opts tells the characteristics of the family. It must be two letters long, and must contain:

  1. a v indicating a covariant family or an i indicating an invariant family;
  2. a c indicating a conforming family or an n indicating a nonconforming family.
The case of the letters does not matter.

Example:

    @BEGIN-EXTENSION
    ...
    @LABEL       5
    @NEW-FAMILY  vc Queue
    @NEW-FAMILY  IN Castle
    ...
    @END-EXTENSION

Binary form

@IMPORTED-FAMILY name

This is similar to a @NEW-FAMILY declaration, but refers to a family that was created elsewhere or that is built into the abstract machine. No options are provided; they are only given when the family is created.

Example:

    @BEGIN-EXTENSION
    ...
    @LABEL           5
    @IMPORTED-FAMILY Queue
    ...
    @END-EXTENSION

Binary form

@NEW-GENUS opt name

Create a new genus called name. Opt is either the letter g indicating a gregarious genus or s indicating a shy genus. The option letters can be upper or lower case.

    @BEGIN-EXTENSION
    ...
    @LABEL       5
    @NEW-GENUS s MAMMAL
    @NEW-GENUS G GRINDABLE
    ...
    @END-EXTENSION

Example.

Binary form

@IMPORTED-GENUS name

This is similar to a @NEW-GENUS declaration, but it refers to a genus that has been imported from another package or that is built into the abstract machine.

Example:

    @BEGIN-EXTENSION
    ...
    @LABEL          5
    @IMPORTED-GENUS MAMMAL
    ...
    @END-EXTENSION

Example.

Binary form

@NEW-COMMUNITY opts name

This declaration creates a new parameterized genus called name. Opts tells characteristics of the new parameterized genus. It must contain one of each of the following letters:

  1. a g if it is gregarious, or a s if it is shy;
  2. a v if it is covariant, or an i if it is invariant;
  3. a c if it is conforming, or an n if it is nonconforming.
The case of the option letters does not matter.

Example:

    @BEGIN-EXTENSION
    ...
    @LABEL          5
    @NEW-COMMUNITY  svc COLLECTION
    ...
    @END-EXTENSION

Binary form

@IMPORTED-COMMUNITY

Refer to a parameterized genus that has previously been defined in an imported package or that is built into the abstract machine.

Example:

    @BEGIN-EXTENSION
    ...
    @LABEL               5
    @IMPORTED-COMMUNITY  COLLECTION
    ...
    @END-EXTENSION

Binary form

@RELATE A B

Let TA be the species, genus, etc. that is defined at global label A, and let TB be what is defined at global label B. Declare that TA is beneath TB in the hierarchy.

Example:

    @BEGIN-EXTENSION
    ...
    @LABEL            5
    @IMPORTED-GENUS   MAMMAL
    @LABEL            6
    @NEW-SPECIES      Kangaroo
    @RELATE           6 5       % A Kangaroo is a kind of MAMMAL.
    ...
    @END-EXTENSION

Example.

Binary form

@MEET A B C

Let TA be what is defined at global label A, etc. Declare that the meet (intersection) of TA and TB is TC.

Example:

    @BEGIN-EXTENSION
    ...
    @LABEL            5
    @IMPORTED-GENUS   MAMMAL
    @LABEL            6
    @NEW-GENUS        HOPPER
    @LABEL            7
    @NEW-SPECIES      Kangaroo
    @MEET             5 6 7      
    ...
    @END-EXTENSION

Binary form

@EMPTY-MEET A1 ... An

Let T1 be what is declared at global label A1, etc. Declare that the meet of T1,...,Tn is empty. That is, no species belongs to all of these things.

Example:

    @BEGIN-EXTENSION
    ...
    @LABEL            12
    @IMPORTED-GENUS   MAMMAL
    @LABEL            13
    @NEW-GENUS        REPTILE
    @EMPTY-MEET       12 13      
    ...
    @END-EXTENSION

Binary form

@DEFAULT L opt

Indicate a default for the genus or parameterized genus at global label L. This declaration is followed by a sequence of instructions that build the default species and put it onto the type stack, followed by an END-SPECIES instruction. Alternatively, a @DEFAULT declaration can be followed immediately by END-SPECIES to cause this genus not to have a default.

Example:

    @BEGIN-EXTENSION
    ...
    @LABEL            12
    @IMPORTED-GENUS   MAMMAL
    @LABEL            13
    @IMPORTED-SPECIES Kangaroo
    @DEFAULT          12
    SPECIES-ID	      13
    END-SPECIES      
    ...
    @END-EXTENSION

Binary form


Declarations: Creating new exceptions and exception sets

@EXCEPTION opt name

Create a new exception or kind of exception called name. Opt is either missing, indicating that this exception is initially not trapped, or is t indicating that this is initially trapped.

An @EXCEPTION declaration can optionally be followed, starting on the next line, by a string constant surrounded by quotes. The string constant is the description of the exception. (See EXCEPTION-STRING.)

After the string (or after the @EXCEPTION declaration if there is no string) is an optional sequence of species-building instructions that puts the content-species of the exception onto the type stack. This sequence of instructions is followed by END-SPECIES. If no species is given, then END-SPECIES should occur immediately.

An @EXCEPTION declaration is used to create a new exception. If you want to use an exception that was created in another package, use an @ID declaration and look up the exception identifier with species ExceptionSpecies.

Binary form

@NEW-EXCEPTION-SET name

Create a new initially empty exception set called name. This is normally preceded by a label declaration, and the exception set is referred to by that label.

Binary form

@NEW-SIMPLE-EXCEPTION-SET name mem

Create a new exception set called name that only contains exception or class of exceptions mem. This is normally preceded by a label declaration, and the exception is referred to by that label.

Binary form

@IMPORTED-EXCEPTION-SET name

Refer to an exception set defined in another package or that is built into the abstract machine. This exception set must have already been imported or defined. This is normally preceded by a label declaration, and the exception is referred to by that label.

Binary form

@EXTEND-EXCEPTION-SET A B

Add the exception or class of exceptions declared at label A to the exception set declared at label B. The exception set being extended must have been created using @NEW-EXCEPTION-SET, not using @NEW-SIMPLE-EXCEPTION-SET.

Binary form


Miscellaneous declarations

@IMPORT path

Read the interface part of package path, given as a full path name of the file.

Example:

    @IMPORT  /home/myself/mypackage

Binary form

@BEGIN-IMPLEMENTATION

This declaration separates the interface part of a package from the implementation part. An import of a package will not read beyond this. This also indicates a possible package name change, if the package has two names.

Binary form


Species building instructions

STD-SPECIES name

Push a standard species or parameterized species onto the type stack. The possible values of name are

Example:

    STD-SPECIES Boolean

Example.

Binary form

STD-SECONDARY-SPECIES name

Push a standard species or parameterized species onto the type stack. The possible values of name are

Example:

    STD-SECONDARY-SPECIES ANY

Binary form

SPECIES-ID L

Push the species or parameterized species defined at global label L onto the type stack.

Example:

    SPECIES-ID  4

Binary form

STD-SPECIES-VAR name

Push a variable that ranges over genus or parameterized genus name. The possible values of name are

Example:

    STD-SPECIES-VAR  ANY

Example

Binary form

STD-PRIMARY-SPECIES-VAR name

Similar to STD-SPECIES-VAR, but push a variable that can only have a primary species as its value.

Binary form

STD-SECONDARY-SPECIES-VAR name

Similar to STD-SPECIES-VAR, but push a variable that can only have a secondary species as its value.

Binary form

SPECIES-VAR L

Push a variable that ranges over the genus or parameterized genus labeled by global label L.

Example:

    SPECIES-VAR  40

Binary form

PRIMARY-SPECIES-VAR L

Similar to SPECIES-VAR, but push a variable that can only have a primary species as its value.

Binary form

SECONDARY-SPECIES-VAR L

Similar to SPECIES-VAR, but push a variable that can only have a secondary species as its value.

Binary form

FUNCTION-SPECIES

Pop B then A from the type stack, then push A -> B. That is, modify the type stack as follows.

Type stack
 before    after  
B A -> B
A  

Example.

Binary form

PAIR-SPECIES

Pop B then A from the type stack, then push (A, B). That is, modify the type stack as follows.

Type stack
 before    after  
B (A, B)
A  

Example

Binary form

LIST-SPECIES

Pop A from the type stack, then push List(A). That is, modify the type stack as follows.

Type stack
 before    after  
A List(A)

Example.

Binary form

BOX-SPECIES

Pop A from the type stack, then push Box(A). That is, modify the type stack as follows.

Type stack
 before    after  
A Box(A)

Binary form

FAM-MEM-SPECIES

Pop F then A from the type stack, then push F(A), where F is a parameterized species or variable that stands for a parameterized species. That is, modify the type stack as follows.

Type stack
 before    after  
F F(A)
A  

Binary form

SECONDARY-DEFAULT

Mark the variable on top of the type stack as preferring a secondary default. Do not modify the type stack itself. If the top of the type stack is not a variable, do nothing.

Binary form


Taking apart species on the type stack

UNPAIR-SPECIES

Modify the type stack in one of the following ways.

Type stack
 before    after  
(A, B) B
  A

Type stack
 before    after  
A -> B B
  A

Type stack
 before    after  
F(A) F
  A

If the top of the type stack does not have any of these forms then it is an error.

Example

Binary form

HEAD-SPECIES

Modify the type stack in one of the following ways.

Type stack
 before    after  
(A, B) A

Type stack
 before    after  
A -> B A

Type stack
 before    after  
F(A) A

Binary form

TAIL-SPECIES

Modify the type stack in one of the following ways.

Type stack
 before    after  
(A, B) B

Type stack
 before    after  
A -> B B

Type stack
 before    after  
F(A) F

Binary form

POP-SPECIES

Pop the type stack. That is, modify the type stack in the following way.

Type stack
 before    after  
A  

Example

Binary form

SWAP-SPECIES

Swap the top two things on the type stack. That is, modify the type stack in the following way.

Type stack
 before    after  
A B
B A

Binary form


Using the type store and the static environment

CLEAR-SPECIES-STORE

Remove all species from the species store and make the next index to be filled be 0.

Binary form

STORE-SPECIES

Pop the type stack and store the popped thing at the next available index in the species store. Add 1 to the next available index. Successive STORE-SPECIES instructions store at indices 0, 1, 2, ...

Type stack
 before    after  
A  

Binary form

STORE-AND-LEAVE-SPECIES

Store what is on top of the type stack at the next available index in the species store. Do not modify the type stack. Add 1 to the next available index.

Type stack
 before    after  
A A

Example.

Binary form

GET-SPECIES n

Fetch what was stored at index n in the type store and push it onto the type stack.

Type stack
 before    after  
  A

Example.

Binary form

GLOBAL-FETCH-SPECIES n

Fetch what was stored at index n in the current function's static environment and push it onto the type stack.

Type stack
 before    after  
  A

Example

Binary form


Handling polymorphic types

UNIFY

Pop the top two species from the type stack and unify them. Bindings of variables are put into the current thread's species variable binding table. If unification fails, then fail with exception speciesX.

Type stack
 before    after  
B  
A  

Binary form

CONSTRAIN-SPECIES

Pop B then A from the type stack. Do not push anything back. That is, modify the type stack as follows.

Type stack
 before    after  
B  
A  

Add a constraint A >= B. That is, constrain the values of variables in A and B so that this must be true.

Binary form

FREEZE-SPECIES

Replace the type stack top by a copy of itself, replacing each bound species variable by the species to which it is bound. Bindings are found in the current thread's binding table.

Type stack
 before    after  
A
A'

Binary form

PUSH-SPECIES-BINDINGS

Push the current thread's species binding table onto its binding stack so that it can be restored later using POP-SPECIES-BINDINGS.

Binary form

POP-SPECIES-BINDINGS

Pop the current thread's species binding table stack and put the popped table into its species binding table.

Binary form

COMMIT-SPECIES-BINDINGS

Replace the top of the current thread's species binding table stack by the current species variable binding table. This will ensure that a subsequent POP-SPECIES-BINDING instruction will leave the table the way it is now.

Binary form


Species as values

SPECIES-AS-VALUE

Pop the type stack and push the popped species onto the data stack.

Data stack
 before    after  
  T
Type stack
 before    after  
T  

Binary form

DS-MAKE-SPECIES

Pop the name of a species or parameterized species (a string) from the data stack, and push the corresponding species or parameterized species in its place. That is, modify the data stack as follows.

Data stack
 before    after  
name** : List(Char) T** : ASpecies

Binary form

DS-FUNCTION-SPECIES

Modify the data stack as follows.

Data stack
 before    after  
B** : ASpecies (A -> B)** : ASpecies
A** : ASpecies  

Binary form

DS-PAIR-SPECIES

Modify the data stack as follows.

Data stack
 before    after  
B** : ASpecies (A, B)** : ASpecies
A** : ASpecies  

Binary form

DS-FAM-MEM-SPECIES

Modify the data stack as follows.

Data stack
 before    after  
A** : ASpecies (F(A))** : ASpecies
F** : AFamily  

Binary form

DS-UNFUNCTION-SPECIES

Get the domain and codomain of a function species. Modify the data stack as follows.

Data stack
 before    after  
(A -> B)** : ASpecies (A, B)** : (ASpecies, ASpecies)

If the species on the data stack is not a function species then fail with exception testX.

Binary form

DS-UNPAIR-SPECIES

Get the components of a cartesian product species. Modify the data stack as follows.

Data stack
 before    after  
(A, B)** : ASpecies (A, B)** : (ASpecies, ASpecies)

If the species on the data stack is not a cartesian product then fail with exception testX.

Binary form

DS-UNFAM-MEM-SPECIES

Get the family and parameter from a species that is constructed by a family. Modify the data stack as follows.

Data stack
 before    after  
(F(A))** : ASpecies (F, A)** : (AFamily, ASpecies)

If the species on the data stack is not constructed by a family, fail with exception testX.

Binary form

DS-COMPARE-SPECIES

Modify the data stack as follows.

Data stack
 before    after  
B** : ASpecies C** : Natural
A** : ASpecies  

Compare species A and B. C is 0 if A = B, 1 if A > B and 2 if A < B.

Binary form

DS-SPECIES-COMPATIBLE

Modify the data stack as follows.

Data stack
 before    after  
A** : ASpecies R* : Boolean
X**  

X can be of any secondary species, and so must be tagged by a species. Get the species tag T of S. The result R is true if T is <= A, and is false otherwise.

Binary form

DS-PRIMARY?

Modify the data stack as follows.

Data stack
 before    after  
A** : ASpecies or AFamily R* : Boolean

The result R is true if A is a primary species or family and false otherwise.

Binary form

DS-SPECIES-TO-STRING

Get a string that describes a species or family.

Data stack
 before    after  
A** : ASpecies or AFamily S** : List(Char)

Binary form


Building the static environment

GET-GLOBAL-ID L

This instruction should only be used in the static environment building part of a @DEFINE or @EXECUTE declaration.

Pop a species T from the type stack. Get the definition of the name (say, name) defined at label L (by an @ID declaration) of species T from the global definition table. Store the value obtained at the next available slot in the static environment.

If there is no such definition, this instruction will continue, but an attempt to get this identifier and evaluate it will fail with exception noDefX(name:T).

The species T of this identifier is also stored in the static environment. An attempt to get a species at the offset of this global identifier will get species T.

Example.

Binary form

SPECIES-ONLY

This instruction should only be used in the static environment building part of a @DEFINE or @EXECUTE declaration.

Pop a species T from the type stack and store it at the next available slot in the static environment.

Example

Binary form


Computation: Data stack manipulation

DUP

Modify the data stack as follows.

Data stack
 before    after  
A A
  A

Binary form

POP

Modify the data stack as follows.

Data stack
 before    after  
A  

Binary form

SWAP

Modify the data stack as follows.

Data stack
 before    after  
A B
B A

Binary form


Computation: Constants

HERMIT

Push (). Modify the data stack as follows.

Data stack
 before    after  
  ()*

Binary form

ZERO

Push 0. Modify the data stack as follows.

Data stack
 before    after  
  0** : Integer

Binary form

SMALL-INT n

Modify the data stack as follows.

Data stack
 before    after  
  n** : Integer

Here n must be an integer from 0 to 255.

Example.

Binary form

CONST L

Push the constant defined at global label L onto the data stack. That label must occur prior to this instruction in the program. Modify the data stack as follows.

Data stack
 before    after  
  C*

where C is the constant defined at global label L.

Example.

Binary form


Computation: Numbers and arithmetic

ZERO?

Test for 0. Modify the data stack as follows.

Data stack
 before    after  
N** : (any numeric species) R** : Boolean

The result R is true if N is 0 and is false otherwise.

Binary form

ODD?

Test for an odd number. Modify the data stack as follows.

Data stack
 before    after  
N** : Integer R** : Boolean

The result R is true if N is odd and is false otherwise.

Binary form

SIGN

Modify the data stack as follows.

Data stack
 before    after  
N** : (any numeric species) R** : Integer

The result R = -1 if N < 0, R = 0 if N = 0 and R = 1 if N > 0.

Binary form

PLUS

Modify the data stack as follows.

Data stack
 before    after  
Y** : (any numeric species) (X + Y)** : (a numeric species)
X** : (any numeric species)  

Compute the sum of two numbers. The result species depends on the parameter species, and is determined by using COMPATIFY-NUMBERS.

Binary form

MINUS

Modify the data stack as follows.

Data stack
 before    after  
Y** : (any numeric species) (X - Y)** : (a numeric species)
X** : (any numeric species)  

Compute the difference between two numbers. The result species depends on the parameter species, and is determined by using COMPATIFY-NUMBERS.

Binary form

ABSDIFF

Modify the data stack as follows.

Data stack
 before    after  
Y** : (any numeric species) ( |X - Y| )** : (a numeric species)
X** : (any numeric species)  

Compute the absolute difference between two numbers. The result species depends on the parameter speciess, and is determined by using COMPATIFY-NUMBERS.

Binary form

TIMES

Modify the data stack as follows.

Data stack
 before    after  
Y** : (any numeric species) (X * Y)** : (a numeric species)
X** : (any numeric species)  

Compute the product two numbers. The result species depends on the parameter speciess, and is determined by using COMPATIFY-NUMBERS.

Binary form

DIVIDE

Modify the data stack as follows.

Data stack
 before    after  
Y** : (any numeric species) (X / Y)** : (a numeric species)
X** : (any numeric species)  

Compute the quotient of two numbers. The result species depends on the parameter speciess, and is determined by using COMPATIFY-NUMBERS.

Binary form

GCD

Modify the data stack as follows.

Data stack
 before    after  
Y** : Natural gcd(X, Y)** : Natural
X** : Natural  

Compute the greatest common divisor of two nonnegative integers. If both numbers are 0, then this instruction fails with exception domainX("gcd(0,0)"). It is an error if either of X or Y is negative.

Binary form

POW

Modify the data stack as follows.

Data stack
 before    after  
Y** : Integer (XY)** : (any numeric species)
X** : (any numeric species)  

Compute a number to an integer power. The result species is the same as the species of X. If Y < 0, then the species of X must be either Rational or Real. If both X and Y are 0 then this instruction fails with exception domainX("0^0").

Binary form

NEGATE

Modify the data stack as follows.

Data stack
 before    after  
X** : (any numeric species) (-X)** : (the same numeric species)

Binary form

ABS

Modify the data stack as follows.

Data stack
 before    after  
X** : (any numeric species) ( |X| )** : (the same numeric species)

Binary form

RECIPROCAL

Modify the data stack as follows.

Data stack
 before    after  
X** : Rational or Real (1/X)** : Rational or Real

Binary form

MAKE-RAT

Modify the data stack as follows.

Data stack
 before    after  
Y** : Integer (X/Y)** : Rational
X** : Integer  

Binary form

INT-DIVIDE

Modify the data stack as follows.

Data stack
 before    after  
Y** : Natural (Q, R)** : (Integer,Integer)
X** : Integer  

Compute the quotient Q and remainder R when X is divided by Y. It is required that Y > 0. Q and R satisfy the following requirements.

  1. Q*Y + R = X
  2. 0 <= R < Y

If Y = 0 this instruction fails with exception domainX("divide by zero"). If Y < 0 then this instruction fails with exception domainX("integer divide by negative").

Binary form

INTEGER-RECIPROCAL

Modify the data stack as follows.

Data stack
 before    after  
X** : Natural (m, e)** : (Integer, Integer)

Let b be the internal numeric base. This instruction choose m and e so that m*be is an approximation of 1/X. Integer m has about the same number of base b digits as does X.

X must be a positive integer. If X is 0 this instruction fails with exception domainX("divide by zero"). If X < 0 this instruction fails with exception domainX("integer divide by negative").

Binary form

SQRT

Modify the data stack as follows.

Data stack
 before    after  
X** : Real sqrt(X)** : Real

The square root is computed to standard precision, even if X has high precision.

Binary form

EXP

Modify the data stack as follows.

Data stack
 before    after  
X** : Real exp(X)** : Real

exp(X) is eX. It is computed to standard precision, even if X has high precision.

Binary form

LN

Modify the data stack as follows.

Data stack
 before    after  
X** : Real ln(X)** : Real

ln(X) is the natural logarithm of X. It is computed to standard precision, even if X has high precision.

Binary form

SIN

Modify the data stack as follows.

Data stack
 before    after  
X** : Real sin(X)** : Real

The result is computed to standard precision, even if X has high precision.

Binary form

INVTAN

Modify the data stack as follows.

Data stack
 before    after  
X** : Real tan-1(X)** : Real

The result is computed to standard precision, even if X has high precision.

Binary form

FLOOR

Modify the data stack as follows.

Data stack
 before    after  
X** : (any numeric species) floor(X)** : Integer

The result is the largest integer that is not greater than X.

Binary form

CEILING

Modify the data stack as follows.

Data stack
 before    after  
X** : (any numeric species) ceiling(X)** : Integer

The result is the smallest integer that is not less than X.

Binary form

TO-NATURAL

Modify the data stack as follows.

Data stack
 before    after  
X** : (any numeric species) X** : Natural

X is converted to Natural. The conversion is only possible if X is some representation of a nonnegative integer. This instruction fails with exception conversionX if the conversion is not possible.

Binary form

TO-INTEGER

Modify the data stack as follows.

Data stack
 before    after  
X** : (any numeric species) X** : Integer

X is converted to Integer. The conversion is only possible if X is some representation of an integer. This instruction fails with exception conversionX if the conversion is not possible.

Binary form

TO-RATIONAL

Modify the data stack as follows.

Data stack
 before    after  
X** : (any numeric species) X** : Rational

X is converted to Rational.

Binary form

TO-REAL

Modify the data stack as follows.

Data stack
 before    after  
X** : (any numeric species) X** : Real

X is converted to Real.

Binary form

AS

Modify the data stack as follows.

Data stack
 before    after  
Y** : (any numeric species) X'** : (same species as Y)
X** : (any numeric species)

X' is the result of converting X to the same species as Y. If the conversion is not possible, this instruction fails with exception conversionX.

Binary form

STRING-TO-NATURAL

Modify the data stack as follows.

Data stack
 before    after  
S** : List(Char) N** : Natural

Convert a string S of decimal digits to a natural number. The string can contain leading and trailing white space, defined as a sequence of spaces, tabs, linefeeds and carriage-returns. This instruction fails with exception conversionX if S is not a string of decimal digits, optionally preceded or followed by white space.

Binary form

STRING-TO-INTEGER

Modify the data stack as follows.

Data stack
 before    after  
S** : List(Char) N** : Integer

Convert a string S to an integer. S must be in decimal notation, optionally preceded by a + or - sign. The string can contain leading and trailing white space, defined as a sequence of spaces, tabs, linefeeds and carriage-returns. This instruction fails with exception conversionX if S is not an optionally signed string of decimal digits, optionally preceded or followed by white space.

Binary form

STRING-TO-RATIONAL

Modify the data stack as follows.

Data stack
 before    after  
S** : List(Char) N** : Rational

Convert a string S to a rational number. The string consists of

  1. Optional leading white space.
  2. An optional + or - sign.
  3. A sequence of zero or more decimal digits
  4. An optional period followed by zero or more decimal digits.
  5. An optional E or e followed by an optional + or - sign followed by a sequence of one or more decimal digits.
  6. Optional trailing white space.
The number must contain at least one decimal digit, either before or after the decimal point. White space can consist of spaces, tabs, linefeeds and carriage returns.

This instruction fails with exception conversionX if S is not of the correct form.

Binary form

STRING-TO-REAL

Modify the data stack as follows.

Data stack
 before    after  
S** : List(Char) N** : Real

Convert a string S a real number. The form is identical to the form for STRING-TO-RATIONAL.

This instruction fails with exception conversionX if S is not of the correct form.

Binary form

HEX-TO-NAT

Modify the data stack as follows.

Data stack
 before    after  
S** : List(Char) N** : Natural

Convert a string of hexadecimal digits to a natural number. The digits can include the first six letters of the alphabet, either upper or lower case. This instruction fails with exception conversionX if S is not of the correct form.

Binary form

NAT-TO-HEX

Modify the data stack as follows.

Data stack
 before    after  
N** : Natural S** : List(Char)

Convert a natural number to a string of hexadecimal digits.

Binary form

NUM-DIGITS

Modify the data stack as follows.

Data stack
 before    after  
X** : Integer or Real N** : Natural

N is an approximation of the number of internal digits needed to represent X, or the number of internal digits in the mantissa of X for a real number.

Binary form

NUM-DECIMAL-DIGITS

Modify the data stack as follows.

Data stack
 before    after  
X** : Integer or Real N** : Natural

N is an approximation of the number of decimal digits needed to represent X, or the number of decimal digits in the mantissa of X for a real number.

Binary form

PULL-APART-REAL

Modify the data stack as follows.

Data stack
 before    after  
X** : Real (m, e)** : (Integer, Integer)

This instruction computes integers m and e such that X = m*be, where b is the internal base.

Binary form

BUILD-REAL

Modify the data stack as follows.

Data stack
 before    after  
(m, e)** : (Integer, Integer) (m*be)** : Real

This instruction is the inverse of PULL-APART-REAL.

Binary form

GET-PRECISION

Modify the data stack as follows.

Data stack
 before    after  
  P** : Natural

The result P is the current content of box precision for the current thread, but converted to internal digits rather than in decimal digits.

Binary form


Computation: Conversion to string

TO-STRING

Modify the data stack as follows.

Data stack
 before    after  
X** S** : List(Char)

The result S is a string that describes X. The species that X can have are as follows.

What TO-STRING can convert
Integer S is a decimal representation of X.
Rational S is a string of the form "n/d" where n is an integer and d is a positive integer. For example, if X is 1/3 then S is "1/3". If the denominator is 1 then a rational number is shown as an integer.
Real S is a string that describes real number X. The format is chosen by the system. If you need a particular format, use TO-STRING-FORMATTED.
A function S is a string that describes function X. It has the form "(function name:species)" where name is the function name and species is this function's species.

Binary form

TO-STRING-FORMATTED

Modify the data stack as follows.

Data stack
 before    after  
F** S** : List(Char)
X**  

The result S is a string that describes X, using F as formatting information. The species that X and F can have are as follows.

Formats
X : Integer The format F must be a natural number. S is a decimal representation of X in at least F spaces, padded on the left with blanks. Padding will be done only if X has fewer than F digits, in which case S will have exactly F characters.
X : Rational

F can be either a natural number or a pair of natural numbers. A natural number N has the same effect as (N, 0).

Suppose F is (a,b). Then S is a string of the form "n/d" where d is a positive integer formatted with format parameter b, and the entire string is padded up to a characters by padding on the left with blanks if necessary. For example, if X is 1/3 and F is (5,2) then S is "   1/ 3".

X : Real

The format parameter F can be a natural number, a pair of natural numbers or a triple (n, (d, e)). If F is 0 then the number is formatted by the interpreter in a way that it chooses. A natural number n > 0 is equivalent to (n, (0, 0)). A pair (n,d) is equivalent to (n, (d, 0)).

Suppose that F is (n, d, e). If e is 0 then X is formatted in fixed point style, with a total of n or more spaces (padded with blanks on the left if necessary) and with d digits to the right of the decimal point. If d is 0, then no decimal point is shown.

If e > 0 then X is formatted in scientific notation, with an E followed by a signed exponent of 10. Number e tells the number of digits, excluding the sign, to use for the exponent.

Binary form


Computation: Comparisons

COMPARE

Modify the data stack as follows.

Data stack
 before    after  
Y** : (any numeric species) R** : Natural
X** : (any numeric species)  

The result R is 0 if X = Y, 1 if X > Y, and 2 if X < Y.

Binary form

EQ

Modify the data stack in one of the following ways

Data stack
 before    after  
Y** : (any numeric species) R** : Boolean
X** : (any numeric species)  

Data stack
 before    after  
Y* : Box(B) S** : Boolean
X* : Box(A)  

Data stack
 before    after  
Y*** : List(numeric species) W** : Boolean
X*** : List(numeric species)  

The result R is true if X = Y, and false otherwise. Result S is true if X and Y are the same box, and false otherwise. Result W is true if X and Y are the same string or list of numbers.

Binary form

NE

NE is similar to EQ, but it pushes false when EQ would push true, and it pushes true when EQ would push false.

Binary form

LT

Modify the data stack as follows.

Data stack
 before    after  
Y** : (any numeric species) R** : Boolean
X** : (any numeric species)  

The result R is true if X < Y, and false otherwise.

Example

Binary form

LE

Modify the data stack as follows.

Data stack
 before    after  
Y** : (any numeric species) R** : Boolean
X** : (any numeric species)  

The result R is true if X <= Y, and false otherwise.

Binary form

GT

Modify the data stack as follows.

Data stack
 before    after  
Y** : (any numeric species) R** : Boolean
X** : (any numeric species)  

The result R is true if X > Y, and false otherwise.

Binary form

GE

Modify the data stack as follows.

Data stack
 before    after  
Y** : (any numeric species) R** : Boolean
X** : (any numeric species)  

The result R is true if X >= Y, and false otherwise.

Binary form


Computation: Booleans

FALSE

Modify the data stack as follows.

Data stack
 before    after  
  false*

Binary form

TRUE

Modify the data stack as follows.

Data stack
 before    after  
  true*

Binary form

NOT

Modify the data stack as follows.

Data stack
 before    after  
X* : Boolean (not X)* : Boolean

Binary form


Computation: Lists, strings and cartesian products

NIL

Modify the data stack as follows.

Data stack
 before    after  
  []*

Example.

Binary form

NIL?

Modify the data stack as follows.

Data stack
 before    after  
X* : List(T) R* : Boolean

The result R is true if X is [], and false if X is not [].

Example

Binary form

NONNIL-TEST

Modify the data stack as follows.

Data stack
 before    after  
X* : List(T) X* : List(T)

This instruction fails with exception testX if X is []. Otherwise, it does nothing.

Binary form

NONNIL-FORCE

Modify the data stack as follows.

Data stack
 before    after  
X* : List(T) X* : List(T)

This instruction fails with exception testX if X is []. If X is an unbound unprotected unknown, then it binds X to a list having an unknown head and an unknown tail, using two new unbound, unprotected unknowns of the same flavor as X. (If X is shared, the two new unknowns are also shared. If X is nonshared, the two new unknowns are also nonshared.) If X is already known to be a nonempty list, this instruction does nothing.

Binary form

NIL-FORCE

Modify the data stack as follows.

Data stack
 before    after  
X* : List(T X* : List(T)

This instruction fails with exception testX if X is not []. If X is an unbound unprotected unknown, then it binds X to []. If X is [], this instruction does nothing.

Binary form

PAIR

Modify the data stack in one of the following ways

Data stack
 before    after  
Y (X, Y)*
X  

Data stack
 before    after  
Y (X :: Y)*
X  

The ordered pair (X, Y) and the list X::Y (whose head is X and whose tail is Y) have the same representation, so this instruction builds both.

Example.

Binary form

MULTI-PAIR n

Perform n PAIR instructions.

Binary form

HEAD

Modify the data stack in one of the following ways.

Data stack
 before    after  
(X, Y)* X

Data stack
 before    after  
(X :: Y)* X

This instruction fails with exception emptyListX if the stack contains [].

Example

Binary form

LAZY-HEAD

Modify the data stack in one of the following ways.

Data stack
 before    after  
(X, Y) X

Data stack
 before    after  
X :: Y X

This instruction is the same as HEAD, except that the value pushed is lazy. The intial top of the stack is not evaluated immediately. If there is a failure, then the failure will occur when this value is forced, not immediately.

Binary form

TAIL

Modify the data stack in one of the following ways.

Data stack
 before    after  
(X, Y)* Y

Data stack
 before    after  
(X :: Y)* Y

This instruction fails with exception emptyListX if the stack contains [].

Example

Binary form

LAZY-TAIL

Modify the data stack in one of the following ways.

Data stack
 before    after  
(X, Y) Y

Data stack
 before    after  
X :: Y Y

This instruction is the same as TAIL, except that the value pushed is lazy. The intial top of the stack is not evaluated immediately. If there is a failure, then the failure will occur when this value is forced, not immediately.

Binary form

ACTIVE-HEAD

Same as HEAD, but if the top of the stack is initially an unbound unprotected unknown, then bind it to a pair of unbound unprotected unknowns first. Preserve the unknown flavor.

Binary form

ACTIVE-LAZY-HEAD

Same as LAZY-HEAD, but when the result is forced, if the value whose head is being taken is an unbound unprotected unknown, then bind it to a pair of unbound unprotected unknowns first. Preserve the unknown flavor.

Binary form

ACTIVE-TAIL

Same as TAIL, but if the top of the stack is initially an unbound unprotected unknown, then bind it to a pair of unbound unprotected unknowns first. Preserve the unknown flavor.

Binary form

ACTIVE-LAZY-TAIL

Same as LAZY-TAIL, but when the result is forced, if the value whose tail is being taken is an unbound unprotected unknown, then bind it to a pair of unbound unprotected unknowns first. Preserve the unknown flavor.

Binary form

MULTI-RIGHT n

Perform n ACTIVE-TAIL instructions.

Binary form

SPLIT

Modify the data stack in one of the following ways.

Data stack
 before    after  
(X, Y)* Y
  X

Data stack
 before    after  
(X :: Y)* Y
  X

This instruction fails with exception emptyListX if the stack contains [].

Binary form

LENGTH

Modify the data stack as follows.

Data stack
 before    after  
X**** : List(T) length(X) : Natural

Binary form

LIMITED-LENGTH

Modify the data stack as follows.

Data stack
 before    after  
N** : Natural R : Natural
L**** : List(T)  

The result R is the length of list L provided that length is at most N. If the length of L is larger than N, then R will be some number larger than N.

Binary form

REVERSE

Modify the data stack as follows.

Data stack
 before    after  
X**** : List(T) reverse(X) : List(T)

reverse(X) is the reversal of list X.

Binary form

APPEND

Modify the data stack as follows.

Data stack
 before    after  
Y : List(T) X + Y : List(T)
X : List(T)  

X + Y is the concatenation of list X followed by list Y.

Binary form

SUBSCRIPT

Modify the data stack as follows.

Data stack
 before    after  
N** : Natural L[N] : T
L**** : List(T)  

Here L[N] indicate the N-th member of L, numbering from 0. So L[0] is the head of L, L[1] the second member of L, etc.

This instruction fails with exception subscriptX if there is no N-th member of L.

Binary form

SUBLIST

Modify the data stack as follows.

Data stack
 before    after  
(M, N)** : (Natural, Natural) R : List(T)
L**** : List(T)  

The result list R is obtained from list L by (1) removing the first M members, and (2) taking a prefix of length N of what is left. For example, if L is [1,2,3,4,5,6,7], M is 2 and N is 3 then R is [3,4,5].

If L has fewer than M members then R is an empty list. If L has M or more members, but fewer than M + N, then R is the result of removing the first M members of L.

Binary form

BITE

Modify the data stack as follows.

Data stack
 before    after  
L**** : List(T) (A, B) : (List(T), List(T))

If L is [], then A = [] and B = []. Otherwise, A and B are chosen so that A is not [], and L = A + B (the concenation A followed by B).

This instruction is intended to extract an "efficient" prefix so that a function can process a list in chunks more efficiently than processing it one member at a time. This function will avoid evaluating promises when it can.

Binary form

SCAN-FOR

Modify the data stack as follows.

Data stack
 before    after  
(P,W,S)** : (Char, Integer, Boolean) (i,r,q) : (Natural, List(Char), Char)
S**** : List(Char)  

Integer W is treated as a bit vector that describes a set of characters. The n-th bit is 1 if character n is in the set, where bits are numbered from 0 starting at the low-order end.

If S is true, then i, r and q are chosen so that

  1. S[i] is the first member of S that is in the set described by W (where indexing in S is from 0);
  2. r is the suffix of S that is obtained by deleting i characters from the start of S;
  3. q is S[i-1] if i > 0, and is P if i = 0.

Binary form

UPTO

Modify the data stack as follows.

Data stack
 before    after  
N** : Integer [M,M+1,...,N]: List(Integer)
M** : Integer  

If M > N then [] is pushed.

Binary form

DOWNTO

Modify the data stack as follows.

Data stack
 before    after  
N** : Integer [M,M-1,...,N]: List(Integer)
M** : Integer  

If M < N then [] is pushed.

Binary form

START-LIST

Modify the data stack as follows.

Data stack
 before    after  
N** : Natural N : Natural
  L

Create a shell L suitable for extending to a fully defined list of length N using ADD-LIST-MEM. This list must be finished using ADD-LIST-MEM N times before it is ready to use. The list that is created uses random-access (packed) representation.

Binary form

ADD-LIST-MEM

Modify the data stack as follows.

Data stack
 before    after  
V N-1
N** : Natural L
L  

Add value V to list L at index N-1. You build a list backwards using these instructions. For example, to create list [10,20,30,40], you could use the following sequence of instructions.

    PUSH-INT 4
    MAKE-START-LIST
    PUSH-INT 40
    ADD-LIST-MEM
    PUSH-INT 30
    ADD-LIST-MEM
    PUSH-INT 20
    ADD-LIST-MEM
    PUSH-INT 10
    ADD-LIST-MEM
    POP              %% List [10,20,30,40] is now on the data stack.

Binary form

MAPPED-LIST

Modify the data stack as follows.

Data stack
 before    after  
F : T -> S (map F L) : List(S)
L : List(T)  

If L is [a,b,c,d] then (map F L) is the list [F(a), F(b), F(c), F(d)]. The list that is created is dynamically mapped, and does not memoize its result. Each time a member of the result list is needed, the corresponding member of L is found, and F is applied to it.

Binary form

MAP-WRAP k

Get the species List(T) -> S stored at index k in the static environment. Modify the data stack as follows.

Data stack
 before    after  
L* : List(T) R

If L is [a,b,c,d] then the result list R is [(a:T), (b:T), (c:T), (d:T)] where each member is tagged with species A. Species A must be a primary species; otherwise this instruction fails with exception speciesX.

Exception. If a member a of list L is already tagged by a species then no new tag is added to a. Instead, a will be placed unchanged into the result list.

Binary form

PACK

Modify the data stack as follows.

Data stack
 before    after  
L**** : List(T) L : List(T)

From a semantic perspective, this instruction has no effect. But it might perform a change or representation. The list on the stack after a PACK will be in random-access, or packed, representation.

Binary form

INTERN-STRING

Modify the data stack as follows.

Data stack
 before    after  
L**** : List(Char) L : List(Char)

From a semantic perspective, this instruction has no effect. But it might perform a change or representation. The string is put into a hash table, and the new L refers to that string. This has two effects on performance. One is that, if you have several copies of the same string, the string will only be stored once. The other is that equality tests are efficient when both strings have been interned. (An equality test between interned strings is done by comparing memory addresses.)

Binary form

STRING-TO-SYMBOL

Modify the data stack as follows.

Data stack
 before    after  
name**** : List(Char) sym : Symbol

Convert a string name into a symbol. This is the same as INTERN-STRING. It puts the string into a hash table.

Binary form


Computation: Bit vectors

BV-AND

Take the bitwise and of two integers. An integer is thought of as standing for its infinite two's comlement representation. so 0 is an infinite vector of 0's, and -1 is an infinite vector of 1's.

Data stack
 before    after  
Y** : Integer (X & Y)** : Integer
X** : Integer  

Binary form

BV-OR

Take the bitwise or of two integers. An integer is thought of as standing for its infinite two's comlement representation. so 0 is an infinite vector of 0's, and -1 is an infinite vector of 1's.

Data stack
 before    after  
Y** : Integer (X | Y)** : Integer
X** : Integer  

Binary form

BV-XOR

Take the bitwise exclusive-or of two integers. An integer is thought of as standing for its infinite two's comlement representation. so 0 is an infinite vector of 0's, and -1 is an infinite vector of 1's.

Data stack
 before    after  
Y** : Integer (X xor Y)** : Integer
X** : Integer  

Binary form

BV-SHL

Shift an integer to the left, pulling in 0 bits on the right end.

Data stack
 before    after  
N** : Natural R** : Integer
X** : Integer  

R is the result of shifting X to the left N bits, pulling in 0 bits on the right. So if Xis 3 and N is 2 then R is 12. X is thought of as standing for its infinite two's comlement representation. so 0 is an infinite vector of 0's, and -1 is an infinite vector of 1's.

Binary form

BV-SHR

Shift an integer to the right.

Data stack
 before    after  
N** : Natural R** : Integer
X** : Integer  

R is the result of shifting X to the right N bits. X is thought of as standing for its infinite two's comlement representation. so 0 is an infinite vector of 0's, and -1 is an infinite vector of 1's.

Binary form

SHIFT-LEFT-DIGITS

Shift an integer to the left by a given number of internal digits.

Data stack
 before    after  
N** : Natural R** : Integer
X** : Integer  

R is the result of shifting X to the left N internal digits, pulling in 0 digits on the right.

Binary form

SHIFT-RIGHT-DIGITS

Shift an integer to the right by a given number of internal digits.

Data stack
 before    after  
N** : Natural R** : Integer
X** : Integer  

R is the result of shifting X to the right N internal digits.

Binary form

BV-SET-BITS

Data stack
 before    after  
(L,K)** : (List(Natural), Boolean) R** : Integer
X** : Integer  

R is the result of setting each bit of X whose index is a member of list L to K. Indexing of bits is from 0, counting from the low order end. So if L is [2,4] and K is 0, then this instruction computes R by setting bits 2 and 4 of X to 0. If X is 31, then R is 11 in this case. X is thought of as standing for its infinite two's comlement representation. so 0 is an infinite vector of 0's, and -1 is an infinite vector of 1's.

Binary form

BV-FIELD

Data stack
 before    after  
(M,N)** : (Natural, Natural) R** : Integer
X** : Integer  

R is the result of shifting X to the right M bits and then keeping only the rightmost N bits of that result, replacing all bits to the left of those N bits by 0. X is thought of as standing for its infinite two's comlement representation. so 0 is an infinite vector of 0's, and -1 is an infinite vector of 1's.

Binary form

BV-MASK

Data stack
 before    after  
N** : Natural R** : Integer

R is a bit vector of N 1 bits with infinitely many 0 bits to the left of them. In terms of numbers, R is 2N-1.

Binary form

BV-MIN

Data stack
 before    after  
X** : Integer (K,R)** : (Natural,Integer)

X an integer thought of as an infinite bit vector. If X > 0 (so the bit vector has infinitely many 0's) then K is the index of the rightmost 1 bit in X, and R is the result of setting that bit to 0 in X. If X < -1 (so the bit vector has infinitely many 1's) then K is the index of the rightmost 0 bit in X, and R is the result of setting that bit to 1. Indices are from the right (low order) end of the number, starting at 0.

If X is either 0 or -1, then this instruction fails with exception domainX("Cannot extract 1 bit from zero bit vector").

Binary form

BV-MAX

Data stack
 before    after  
X** : Integer (K,R)** : (Natural,Integer)

X an integer thought of as an infinite bit vector. If X > 0 (so the bit vector has infinitely many 0's) then K is the index of the leftmost 1 bit in X, and R is the result of setting that bit to 0 in X. If X < -1 (so the bit vector has infinitely many 1's) then K is the index of the leftmost 0 bit in X, and R is the result of setting that bit to 1. Indices are from the right (low order) end of the number, starting at 0.

If X is either 0 or -1, then this instruction fails with exception domainX("Cannot extract 1 bit from zero bit vector").

Binary form


Computation: Enumerate species

ENUM-CHECK n

Check that the top X of the data stack satisfies 0 <= X < n.

Data stack
 before    after  
X** : Integer X** : Integer

If X < 0 or X >= n then this instruction fails with exception conversionX.

Binary form

PRED

Subtract 1 from a natural number, but do not allow the result to be negative.

Data stack
 before    after  
N** : Natural (N-1)** : Natural

If N <= 0 then this instruction fails with exception domainX("predecessor of smallest").

Binary form


Computation: Boxes and arrays

MAKE-EMPTY-NONSHARED-BOX

Push a new empty nonshared box onto the data stack. Modify the data stack as follows.

Data stack
 before    after  
  B* : Box(T)

Binary form

MAKE-EMPTY-SHARED-BOX

Push a new empty shared box onto the data stack. Modify the data stack as follows.

Data stack
 before    after  
  B* : Box(T)

Binary form

EMPTY-BOX?

Modify the data stack as follows.

Data stack
 before    after  
B* : Box(T) R* : Boolean

R is true if box B is empty and false otherwise.

Binary form

ASSIGN

Modify the data stack as follows.

Data stack
 before    after  
X : T ()*
B* : Box(T)  

Store X into box B.

If this box has demons attached to it, run the demons. See ATTACH-DEMON.

When B is a computed box, this instruction performs an application of the assignment function of the computed box. It pushes a new frame on the call stack, and continues with that new frame. The value returned by that function is on the stack when the current function continues with the next instruction.

Binary form

ASSIGN-INIT

This is the same as ASSIGN, but it indicates that this is an initial content for the box. That is no different from ASSIGN for a shared box, but when B is a nonshared box it stores the result not only in the current thread's state but also in a global initial state, where any other thread can find the initial value of this box.

Binary form

ASSIGN-NODEMON

This is the same as ASSIGN, but it does not run demons associated with the box.

Binary form

MAKE-BOX-EMPTY

Modify the data stack as follows.

Data stack
 before    after  
B* : Box(T) ()*

Make box B be empty. If there are any demons associated with B then run them. See ATTACH-DEMON.

When B is a computed box, this instruction performs an application of the assignment function of the computed box. It pushes a new frame on the call stack, and continues with that new frame. The value returned by that function is on the stack when the current function continues with the next instruction.

Binary form

MAKE-BOX-EMPTY-NODEMON

This is similar to MAKE-BOX-EMPTY, but does not run demons associated with the box.

Binary form

CONTENT

Modify the data stack as follows.

Data stack
 before    after  
B* : Box(T) X : T

X is the current content of box B. If B is empty then this instruction fails with exception emptyBoxX.

Binary form

CONTENT-TEST

This is the same as CONTENT but when it fails the exception is testX.

Binary form

STD-BOX name

Modify the data stack as follows.

Data stack
 before    after  
  B : Box(T)

Box B is one of the standard boxes, given by name. The possibilities are as follows.

Standard boxes
Box Description
precision This nonshared box holds the precision for real numbers in decimal digits.
stdin This nonshared box holds the contents of the standard input (a list of characters). This string ends on a lazy value whose evaluation causes more characters to be read. If none are available, the thread that performed the read is blocked.
stdout This nonshared box initially holds a SysOutfile that is bound to the standard output of this process.
traceSockets This nonshared box initially holds false. If set to hold true, actions on sockets will be traced to the standard output.
useCommas This nonshared box initially holds false. If set to hold true, numbers are shown (by TO-STRING or TO-STRING-FORMATTED) with commas every three digits.
cwd This nonshared box holds the current working directory.

Binary form

COMPUTED-BOX

Modify the data stack as follows.

Data stack
 before    after  
(F,(S,L)*)* : (() -> Optional(T), (Optional(T) ->(), Natural -> Boolean)) B* : Box(T)

Build a computed box B. A computed box is simulated by functions.

F is a function that fetches (or simulates fetching) the content of a box. F() returns 0 if the box is empty and returns (v:1) if v is the content of the box.

S is a function that is used to set (or simulate setting) the value of a box. S(v:1) sets the content to v. S(0) makes the box empty.

L is a function that locks and unlocks the box.

Action of the lock/unlock function L
L(0) locks the box. Its return value is ignored.
L(1) unlocks the box. Its return value is ignored.
L(2) unlocks the box completely. Its return value is ignored.
L(3) returns true if the box is locked and false if the box is not locked.

Binary form

NONSHARED-ARRAY

Modify the data stack as follows.

Data stack
 before    after  
N** : Natural A** : List(Box(T))

A is a list of N new empty nonshared boxes. A packed representation is used.

Binary form

SHARED-ARRAY

Modify the data stack as follows.

Data stack
 before    after  
N** : Natural A** : List(Box(T))

A is a list of N new empty shared boxes. A packed representation is used.

Binary form

FLAVOR

Modify the data stack as follows.

Data stack
 before    after  
B* : Box(T) F** : Natural

F is 0 if B is a nonshared box, 1 if B is a shared box, and 2 if B is a computed box.

Binary form

BEGIN-PRESERVE

Push the current state onto the state stack, so that it can be restored later.

Binary form

END-PRESERVE

Pop the state stack and set the state to the popped state.

Binary form

ATTACH-DEMON

Modify the data stack as follows.

Data stack
 before    after  
B* : Box(T)  
F* : (Optional(T, Optional(T)) -> ())  

Attach function F to box B as a demon. When an ASSIGN or EMPTY-BOX instruction performed, just after the assignment is performed F(u,v) is run with parameters u and v that indicate the former and new content of box B. Specifically, u is 0 if B was formerly empty, and is (c:1) if B formerly contained c. Similarly, v is <0 if box B was just emptied (by an EMPTY-BOX instruction) and is (d:1) if an ASSIGN instruction was done that put d into this box.

There is one exception: if an empty box is emptied, the demon is not run.

You can attach several demons to one box. The demons are evaluated in the same order in which they were attached.

Binary form

RANK-BOX

Modify the data stack as follows.

Data stack
 before    after  
B* : Box(T) N** : Natural

N is an number that indicates the current address of box B. This can be used to refer to the box briefly. But be careful. A garbage collection can move a box. See SUPPRESS-COMPACTIFY if you need box ranks not to change.

Binary form

BOX-TO-STRING k

Get the species Box(T) -> A stored at index k in the static environment. Modify the data stack as follows.

Data stack
 before    after  
B* : Box(T) S** : List(Char)

S is string that describes box B. The description is based on the rank of this box.

The species T is only used in some circumstances to determine the content species of the box. It is required when the showing the configuration so that the interpreter can determine which boxes should be shown.

Binary form


Computation: Unknowns

NONSHARED-UNKNOWN

Modify the data stack as follows.

Data stack
 before    after  
  U : T

U is new unbound nonshared unprotected unknown.

Binary form

SHARED-UNKNOWN

Modify the data stack as follows.

Data stack
 before    after  
  U : T

U is new unbound shared unprotected unknown.

Binary form

PROTECTED-NONSHARED-UNKNOWN

Modify the data stack as follows.

Data stack
 before    after  
  (U,K*)* : (T, UnknownKey)

U is new unbound nonshared protected unknown and K is its key. The key is required to bind the unknown.

Binary form

PROTECTED-SHARED-UNKNOWN

Modify the data stack as follows.

Data stack
 before    after  
  (U,K*)* : (T, UnknownKey)

U is new unbound shared protected unknown and K is its key. The key is required to bind the unknown.

Binary form

BIND-UNKNOWN k

Modify the data stack as follows.

If k = 0 then bind an unprotected unknown. The data stack is modified as follows, and unknown U is bound to X.

Data stack
 before    after  
X : T  
U* : T  

If k =/= 0 then modify the data stack as follows.

Data stack
 before    after  
X : T  
(U*,K*) : (T, UnknownKey)  

K must be the correct key for unknown U. Bind U to X.

This instruction fails with exception bindUnknownX if U is not an unbound unknown or if K is not the correct key for U, ir if the unknown is of the wrong kind for the instruction.

Binary form

UNKNOWN?

Modify the data stack as follows.

Data stack
 before    after  
X* R* : Boolean

R is true if X is an unbound unknown, and is false otherwise.

Binary form

PROTECTED-UNKNOWN?

Modify the data stack as follows.

Data stack
 before    after  
X* R* : Boolean

R is true if X is an unbound protected unknown, and is false otherwise.

Binary form

UNPROTECTED-UNKNOWN?

Modify the data stack as follows.

Data stack
 before    after  
X* R* : Boolean

R is true if X is an unbound unprotected unknown, and is false otherwise.

Binary form

SAME-UNKNOWN?

Modify the data stack as follows.

Data stack
 before    after  
Y* R* : Boolean
X*  

R is true if X and Y are the same unbound unknown, and is false otherwise.

Binary form


Computation: Tagging and untagging items

WRAP

Tag an item with a species. Modify the data stack as follows and type stack as follows.

Data stack
 before    after  
X* (X:T)*
Type stack
 before    after  
T  

Exception. If X is an item that is already tagged with a species, then do not add another tag. Leave X as it is. In this case, the data stack and type stack are modified as follows.

Data stack
 before    after  
X (X:T)*
Type stack
 before    after  
T  

Binary form

WRAP-FUN k

Tag an item with a species. The species is the domain of a function species that is stored at index k in the static environment. Suppose that the species at index k is A -> B. Modify the data stack as follows.

Data stack
 before    after  
X* (X:A)*

Exception. If X is already tagged by a species then X is pushed, not (X:A). This instruction will not add another layer of species tag.

Binary form

WRAP-NUMBER k

Get the species stored at index k in the static environment. It should be a function species, A -> B. Pop a number X from the data stack. If X has the form (Y:S) then replace X by Y, and ignore S.

Find the first species in the list (Natural, Integer, Rational, Real) that is consistent with both the representation of X and with species B, and call that species T. Species T is compatible with the representation of X if X could be the representation of a value of that species. Species T is compatible with species B if T <= B in the species hierarchy.

If T = B, or if X already has a species tag, then push X' = X. If T < B and X does not have a species tag then push X' = (X:T).

Modify the data stack as follows.

Data stack
 before    after  
X** X'**

Binary form

UNWRAP

Remove the species tag from an item. Modify the data stack as follows and type stack as follows.

Data stack
 before    after  
(X:T)* X
Type stack
 before    after  
  T

Binary form

IRREGULAR-CHECK

This instruction is intended to be used after applying an irregular function. Modify the data stack and type stack in one of the following ways.

Data stack
 before    after  
X X
Type stack
 before    after  
B  
A  

Data stack
 before    after  
X (X:A)
Type stack
 before    after  
B  
A  

This instruction gets A and B from the type stack. Species A must not contain any unbound variables, but B can contain unbound variables. This instruction adds constraint A <= B. If addition of that constraint makes the hierarchy inconsistent then this instruction fails with exception speciesX.

Adding the new constraint can cause variables in B to become bound. Any remaining unbound variables in B are bound to default values. If, after all variables in B have become bound, B = A, then the item on the data stack is not modified, as shown in the first pair of diagrams. But if it is found that A < B then the value on the top of the data stack is either tagged or retagged with species A, as shown in the second pair of diagrams.

Binary form

ATTACH-ITAG n

Attach a nonnegative integer tag to an item.

Data stack
 before    after  
X (X:n)*

If X is () then the value pushed is just the integer n, not (():n).

Binary form

ATTACH-COMPUTED-ITAG

Attach a nonnegative integer tag to an item.

Data stack
 before    after  
N* (X:N)*
X  

If X is () then the value pushed is just the integer N, not (():N). If N < 0 then this instruction fails with exception domainX("Negative tag").

Binary form

GET-ITAG

Get the integer tag of an item.

Data stack
 before    after  
(X:N)* N** : Natural

Data stack
 before    after  
N** : Integer N** : Integer

Data stack
 before    after  
X* -1*

If the item on top of the data stack is not an integer and is not a tagged value then this instruction replaces the stack top by -1.

Binary form

TEST-ITAG n

Data stack
 before    after  
X* R* : Boolean

The result R is true if X has the form (Y:n) or if X is n, where n is the instruction parameter, and R is false otherwise.

Binary form

REMOVE-ITAG n

Data stack
 before    after  
(X:n)* X

Data stack
 before    after  
N** : Natural ()*

If the item on top of the data stack has tag n or is n then this instruction succeeds, and it pushes the value with the tag removed. An integer is treated as a tagged (). If the item on top of the data stack has any other form then this instruction fails with exception testX.

Binary form

SPLIT-ITAGGED

Data stack
 before    after  
(X:N)* (N, X)*

Data stack
 before    after  
N** : Natural (N, ())**

If the stack top contains a value that has an integer tag or that is a nonnegative integer then push a pair consisting of the tagged value and the tag. Otherwise fail with exception testX.

Binary form


Computation: Functions and function application

FUNCTION L

This instruction creates a function. The overall form is as follows.

Form of FUNCTION instrution
FUNCTION L  
instructions These instructions compute the codomain species of the function and push that onto the type stack.
BEGIN-BODY i Begin the executable part. The number i tells an upper limit on the number of slots that are required in the local environment of the function. See specifying the size of the environment.
instructions These instructions are the body of the function.
LOC-LABEL L The end of the function. Notice that this label is the one that occurs in the FUNCTION instruction.

The function that is created starts with its parameter on top of the data stack. It performs the instructions that follow the BEGIN-BODY instruction. When the function is finished, it should put its result onto the data stack and perform a RETURN or INVISIBLE-RETURN instruction. If it falls through at the LOC-LABEL L instruction without returning, results are undefined.

The function is given the same name as the current activation's name.

After the function is built it is pushed onto the data stack, and the computation that created the function continues running just after LOC-LABEL L.

Modify the data stack as follows, where F is the function that is created.

Data stack
 before    after  
  F

Example: Here is a function f(x) = x + x, where x must have species Integer.

  FUNCTION 1
  STD-SPECIES Integer
  BEGIN-BODY 1
  BIND-AND-LEAVE 0
  FETCH 0
  PLUS
  RETURN
  LOC-LABEL 1

Example

Example

Binary form

APPLY

This instruction applies a function. It pushes a new frame onto the call stack and begins running a function in that new frame. When the function call is done, the function's result will be on top of the data stack.

If you imagine the computation of the function to be performed on the side, and ignore that computation, then the effect is to modify the data stack as follows.

Data stack
 before    after  
F* : S -> T F(A) : T
A : S  

However, what really happens is that a new frame is pushed onto the call stack, causing a new context to be entered. Function F runs in this new context until it performs a RETURN or INVISIBLE-RETURN instruction, causing its frame to be removed from the call stack, and the former context to be continued.

Example.

Binary form

TAIL-APPLY

This instruction is similar in effect to an APPLY instruction. However, the new function's frame in the call stack replaces the current function's frame. This means that, when this function call returns, there is an implicit return from the current function call. So

  TAIL-APPLY
is equivalent to
  APPLY
  RETURN
However, a TAIL-APPLY is more efficient than an APPLY followed by a RETURN.

Example

Binary form

PAIR-APPLY n

This is equivalent to n PAIR instructions followed by APPLY. However, it is more efficient.

Binary form

PAIR-TAIL-APPLY n

This is equivalent to n PAIR instructions followed by TAIL-APPLY. However, it is more efficient.

Example

Binary form

SHORT-APPLY

This is equivalent to APPLY. However, the function that is called is given a short time limit to finish its work. If it does not finish, then its computation becomes deferred (building a promise to continue it) and the deferred value is pushed onto the stack.

Binary form

QEQ-APPLY

For this instruction, a tagged value either has the form (V:N) where N is an integer, or is an integer itself. The tag of (V:N) is N, and the tag of N is N.

This instruction applies an equality testing function, E, to a pair of items, with some special rules. This instruction should only be used when the following are true.

Under those assumptions, this instruction modifies the stack as follows.

Data stack
 before    after  
E : (T, T) -> Boolean E(X, Y) : Boolean
Y* : T  
X* : T  

E is only used, and only evaluated, if the answer could not be determined by using the assumptions about the behavior of E.

Binary form

RETURN

Return to the caller of a function. This instruction should be performed with the function's result on top of the data stack.

Example.

Binary form

INVISIBLE-RETURN

Same as a RETURN, but for a function that wants to remain hidden to the debugger.

Binary form

CALL-LOCAL L

Push the address of the instruction just after this one onto the local-return-address stack, and jump to label L.

Binary form

RETURN-LOCAL

Pop the local-return-address stack, and jump to address that is popped.

Binary form


Computation: Lazy evaluation

TEST-NOT-LAZY

Modify the data stack as follows.

Data stack
 before    after  
X R* : Boolean

The result R is true if X is not a promise, so is known at least to its top level structure. R is false if X is a promise.

Binary form

TEST-NOT-LAZY-MABYE

This is almost the same as TEST-NOT-LAZY, but it occasionally pushes a result of false even when X is not a promise.

Binary form

LAZY L

This instruction creates a promise. The overall form is as follows.

Form of LAZY instruction
LAZY L  
instructions These instructions push the species of the value that is to be computed onto the type stack.
BEGIN-BODY i Begin the executable part. The number i tells an upper limit on the number of slots that are required in the local environment of the instructions to follow. See specifying the size of the environment.
instructions These instructions are the body of the promise.
LOC-LABEL L The end of the body. Notice that this label is the one that occurs in the LAZY instruction.

The promise that is created will be evaluated, when needed, by performing the instructions in the body. Those instructions should finish by performing a RETURN or INVISIBLE-RETURN with the result on top of the data stack. If evaluation of the body falls through at the LOC-LABEL L instruction without returning, results are undefined.

The result of evaluating a promise is memoized. After evaluation, the promise is destroyed and replaced by the computed value.

In a little more detail, what you really get is a control tree representing one or more threads that are attached to this evaluation. When the control tree is created, it gets a copy of the thread-local data structures that were in effect when the promise was created. When a promise is evaluated, it runs effectively as a separate thread, except that it is attached to the promise, and is not in the forest of control trees managed by the interpreter.

It is possible for the body to perform forks, and so for the control tree associated with a promise to have several threads. As soon as one of those threads produces a value, that value is chosen as the value of the promise, and all other threads in the control tree for this promise are destroyed.

If all threads for a promise fail, then evaluation of the promise fails with the exception associated with the last thread to fail. The fact that this computation failed is memoized, and another attempt to evaluate the same promise will immediately fail with the same exception.

After the promise is built by the LAZY instruction, it is pushed onto the data stack, and the computation that created the promise continues running just after LOC-LABEL L.

Modify the data stack as follows, where P is the promise that is created.

Data stack
 before    after  
  P

Example

Binary form

LAZY-RECOMPUTE

When a promise is evaluated, the interpreter remembers the result, and avoids recomputing the result of the promise. But if the promise is created using LAZY-RECOMPUTE, then the interpreter is given permission not to remember the result, and instead to recompute it whenever it is needed. Otherwise, LAZY-RECOMPUTE is the same as LAZY.

It is up to the interpreter when and whether to take advantage of this permission.

Binary form

LAZY-LIST L

This instruction creates a promise. The overall form is as follows.

Form of LAZY-LIST instruction
LAZY-LIST L  
instructions These instructions push the species of the list that is to be computed onto the type stack.
BEGIN-BODY i Begin the executable part. The number i tells an upper limit on the number of slots that are required in the local environment of the instructions to follow. See specifying the size of the environment.
instructions These instructions are the body of the promise.
LOC-LABEL L The end of the body. Notice that this label is the one that occurs in the LAZY-LIST instruction.

A LAZY-LIST instruction creates a promise that works in a similar way to the promise created by a LAZY instruction. The body should put a value on the stack and do a RETURN to produce the value.

The difference between LAZY and LAZY-LIST is in how the value is produced. The body of a LAZY-LIST promise typically forks several threads. As each thread produces a result, that result is accumulated into a list, and that list is the value of the promise.

In more detail, when evaluation of the promise starts, the body runs until the first of the threads produces a value, say V. A list is created whose head is V and whose tail is a promise with the remaining control tree attached to it. When (and if) that tail is computed, computation resumes until another thread produces a value. The control tree is associated with the promise, and will not be run until the promise is forced.

If the body of a LAZY-LIST promise does not produce any values, then the lazy list has value [].

The result of forcing a LAZY-LIST promise is memoized.

After the promise is built by the LAZY-LIST instruction, it is pushed onto the data stack, and the computation that created the promise continues running just after LOC-LABEL L.

Modify the data stack as follows, where P is the promise that is created.

Data stack
 before    after  
  P

Binary form

LAZY-LIST-RECOMPUTE

When a promise is evaluated, the interpreter remembers the result, and avoids recomputing the result of the promise. But if the promise is created using LAZY-LIST-RECOMPUTE, then the interpreter is given permission not to remember the result, and instead to recompute it whenever it is needed. Otherwise, LAZY-LIST-RECOMPUTE is the same as LAZY-LIST.

It is up to the interpreter when and whether to take advantage of this permission.

Binary form

TOP-FORCE

Evaluate the top of the data stack to the point where it is no longer a promise. (There might be more promises deeper in the structure after evaluation.) Leave the result on top of the data stack.

Data stack
 before    after  
X* X*

It is not necessary for you to force promises explicitly. All instructions that need values will force promises where necessary. This instruction is only provided so that you can perform a force at a desired time if that is what you need to do.

Binary form

FULL-FORCE

Evaluate the top of the data stack fully, so that there are no more promises inside its structure. This instruction sees only lists and pairs as structures. It will not force the content of a box.

Data stack
 before    after  
X** X**

Binary form


Computation: Using the environment

FETCH n

Fetch the item stored at index n of the local environment. The local environment is the first one in the environment chain. Modify the data stack as follows.

Data stack
 before    after  
  X

where X is the item found in the environment.

Example.

Binary form

FINAL-FETCH n

This is similar to a FETCH instruction, but the interpreter is given permission to destroy this binding after performing the fetch. Any future fetch of from this index before it has been stored again yields an undefined result. (When the interpreter is run in debug mode, it will not destroy the binding.)

Example.

Binary form

LONG-FETCH n k

This is similar to a FETCH instruction, but the fetch is from the environment in the current chain that is k frames from the front of the list. This moves out k scopes.

Binary form

FINAL-LONG-FETCH n k

This is similar to a LONG-FETCH instruction, but the interpreter is given permission to destroy this binding after performing the fetch. Any future fetch of from this index before it has been stored again yields an undefined result. (When the interpreter is run in debug mode, it will not destroy the binding.)

Binary form

FETCH-GLOBAL n

Fetch the item stored at index n of the static environment (the one at the end of the environment chain). Modify the data stack as follows.

Data stack
 before    after  
  X

where X is the item found in the static environment.

Example.

Binary form

DYNAMIC-FETCH-GLOBAL L

Pop a species T from the type stack. There must be an @ID declaration just after global label L. Let name be the name defined there. Fetch the binding of name of species T directly from the global definition table, and push it onto the data stack.

If there is no such definition, this instruction fails with exception noDefX(name:T).

Binary form

OUTER-BINDING

Pop a species List(Char) -> T from the type stack. Pop a string name from the data stack. Fetch the binding of name of species T directly from the global definition table, and push it onto the data stack. The data stack is modified as follows.

Data stack
 before    after  
name** : List(Char) X
Type stack
 before    after  
List(Char) -> T  

where X is the value obtained from the global definition table.

If there is no such definition, this instruction fails with exception noDefX(name:T).

Binary form

OUTER-BINDING2

Pop a species T and a string name from the data stack. Fetch the binding of name of species T directly from the global definition table, and push it onto the data stack, as a tagged value, tagged by species T. The data stack is modified as follows.

Data stack
 before    after  
T** : ASpecies (X:T)**
name** : List(Char)  

where X is the value obtained from the global definition table.

If there is no such definition, this instruction fails with exception noDefX(name:T).

Binary form

BIND n (name)

Store the item on top of the data stack at index n in the local environment (the first one in the environment chain). Modify the data stack as follows.

Data stack
 before    after  
X  

where X is the item that is stored. (name) is optional. It is the name of this local variable, and is only used for debugging. If omitted, it is taken to be an empty string.

A BIND instruction is followed by a sequence of instructions that build the species of what is being stored by the BIND instruction, leaving the species on top of the type stack, followed by an END-TYPE instruction. The species is only used for debugging, and can be omitted. However, the END-TYPE instruction is required.

Example. to store the top of the stack at offset 2 in the local environment, and to indicate that this offset has name x:

     BIND  2  (x)
     END-TYPE
The above definition omits species information about x. If you know that x has type Integer, you can write
     BIND  2  (x)
     STD-SPECIES  Integer
     END-TYPE
and if you have stored the species of x at offset 3 in the static environment, you can write
     BIND  2  (x)
     GLOBAL-FETCH-SPECIES 3
     END-TYPE

Example.

Binary form

DEAD-BIND n (name)

This is similar to a BIND instruction, but the interpreter is given permission not to do the store, because this value will never be used. (When the interpreter is run in debug mode, it will perform the store.) Like a BIND instruction, it must be followed by (optional) instructions to build a type and an END-TYPE instruction.

Binary form

BIND-AND-LEAVE n (name)

This is similar to a BIND instruction, but it does not remove the item that was stored from the top of the data stack.

Data stack
 before    after  
X X

Example

Binary form

DEAD-BIND-AND-LEAVE n (name)

This is similar to a BIND-AND-LEAVE instruction, but it indicates that the value stored will never be fetched. If it is fetched, the results are undefined. (When run in debug mode, the interpreter will perform the store.)

Binary form

REBIND n

This is similar to a BIND instruction, but does not provide a name, and indicates a change of a value that was already stored. Also, a REBIND instruction is not followed by type-building instructions or an END-TYPE. A REBIND is only allowed to alter the value stored in the environment, not the species.

Binary form

REBIND-AND-LEAVE n

This is similar to a BIND-AND-LEAVE instruction, but does not provide a name, and indicates a change of a value that was already stored. No type-building instructions are used.

Binary form

DEAD-REBIND-AND-LEAVE n

This is similar to a DEAD-BIND-AND-LEAVE instruction, but does not provide a name, and indicates a change of a value that was already stored. There are no type-building instructions.

Binary form

DEFINE L n (name)

Form of DEFINE instruction
DEFINE L n (name)  
instructions These instructions compute the species of the item being defined and push that onto the type stack.
BEGIN-BODY i Begin the executable part. The number i tells an upper limit on the number of slots that are required in the local environment of the function. See specifying the size of the environment.
instructions These instructions are the body of the definition. They compute the value.
LOC-LABEL L The end of the definition. Notice that this label is the one that occurs in the DEFINE instruction.

A promise is created, and that promise is stored in the local environment at index n. The instructions in the body should finish by putting the value being defined on top of the data stack and performing a RETURN or INVISIBLE-RETURN instruction. If evaluation of the body falls through at the LOC-LABEL L instruction without returning, results are undefined.

After the DEFINE is performed, and the computation that did the definition continues running just after LOC-LABEL L.

Binary form

EXIT-SCOPE n

Destroy all bindings beyond the first n bindings in the local environment (the first one in the environment chain). Any future use of these bindings before storing them again yields undefined behavior.

Binary form


Computation: Branches and local labels

LOC-LABEL L

Indicate a local label inside a declaration. The local label number can be preceded by a : as an indication that it is a local label. All instructions that refer to local labels can precede the label number by a :.

Example

Binary form

GOTO L

Jump to the instruction just after local label L.

Binary form

PAIR-GOTO L n

This is the same as n PAIR instructions followed by GOTO L.

Binary form

GOTO-IF-FALSE L

Pop the data stack. If the popped value is false or 0 or [], then jump to local label L. Only an integer value 0 is recognized as an indication 0 here. If the popped value is anything else, do nothing.

Modify the data stack as follows.

Data stack
 before    after  
X*  

Example

Binary form

GOTO-IF-FALSE-LEAVE L

This is similar to GOTO-IF-FALSE, but does not remove the tested value from the data stack.

Data stack
 before    after  
X* X*

Binary form

AND-SKIP L

Look at the top of the data stack. If it is false or 0:Integer or [] then leave the data stack alone and jump to local label L. But if the data stack has another value on it, then pop the data stack and continue with the instruction after this one.

Data stack
 before    after  
false* false*

Data stack
 before    after  
true*  

Binary form

OR-SKIP L

Look at the top of the data stack. If it is false or 0:Integer or [] then pop it from the data stack and continue with the next instruction. But it the data stack has another value on it, then do not pop the data stack, and jump to local label L.

Data stack
 before    after  
true* true*

Data stack
 before    after  
false*  

Binary form


Computation: Failure and exception handling

TEST name

If the top of the data stack is false then fail with standard exception name.

Data stack
 before    after  
X* : Boolean  

Binary form

FAILC name

Fail with standard exception name.

Binary form

FAIL

Pop an exception from the data stack and fail with the popped exception.

Data stack
 before    after  
X* : Exception  

Binary form

PROPAGATE-FAILURE

Fail with the exception that is on the top of the exception stack. If that exception was pushed using a PUSH-EXCEPTION-PROPAGATABLE instruction, then the failure will appear to have been caused at its original location, not at the location of the PROPAGATE-FAILURE instruction.

Binary form

TRY opt L

Add an exception handler to the control. The current thread is a leaf in the control tree. This adds a control node just above the current thread that will catch a failure by jumping to local label L.

The new control node remembers all of the thread-local data structures, and those structures are returned to their values as they were when the TRY instruction was performed when a failure is caught.

Opt consists of up to two characters indicate characteristics of the new control node. You can select or not select each of the following options.

Try options
Option Meaning
 t  This option controls which exceptions this node will catch.
  • If option t is not selected then this node catches all exceptions exception those numbered 0, 1 and 2.

  • If option t is selected, this node catches all exceptions.

 e  This option determines how the new node responds to the case where a thread forks while running beneath it, but not beneath another exception handling node.
  • If option e is not selected, then this node only catches the a failure of the last of the threads. If any thread performs a TRY-THEN that removes this node, then this node will be removed for all threads.

  • If option e is selected, then this node catches every thread that terminates. If one thread performs a TRY-THEN that removes this node, it is still active for other threads that are beneath it in the tree.

Binary form

QUICK-TRY L

This is the same as a TRY with a null option, but it avoids making copies of the thread-local data strutures except for the data stack. As a result, it is more efficient than a TRY instruction. However, it has some restrictions on when it can be used. A quick-try can only be performed when the type stack is empty. The program must not perform any instructions that modify the thread-local data structures, excluding the data stack, before it performs a TRY-THEN instruction or fails. The following instructions are not allowed to be performed betweeen a QUICK-TRY and a TRY-THEN.

Binary form

TRY-THEN

Remove the exception handling node that is just above the current thread's node in the control tree. This indicates exit from that part of the code that is protected by this exception handler.

Binary form

PUSH-EXCEPTION

This can only be performed immediately after catching a failure. It pushes the exception associated with the failure onto the exception stack.

Binary form

PUSH-EXCEPTION-PROPAGATABLE

This is the same as PUSH-EXCEPTION except it pushes a little bit more information with the exception. The additional information is used by a PROPAGATE-FAILURE instruction to know who caused the exception.

Binary form

POP-EXCEPTION

Pop the exception stack. Do nothing with the popped exception.

Binary form

EXCEPTION

Push the exception that is on top of the exception stack onto the data stack. Do not modify the exception stack.

Binary form

PUSH-TRAP

Push the current trap set (the one on top of the trap stack) onto the trap stack, duplicating it. This allows the top trap set to be modified, and the old one to be recovered later.

Binary form

POP-TRAP

Pop the trap stack. This causes the current trap vector to become the one that was beneath the top one on the trap stack.

Binary form

TRAP

Pop an exception set S from the data stack. Modify the current trap set so that all exceptions in set S are trapped. Do not modify the status of any exceptions not in S. The data stack is modified as follows.

Data stack
 before    after  
S** : ExceptionSetSpecies  

Binary form

UNTRAP

Pop an exception set S from the data stack. Modify the current trap set so that all exceptions in set S are not trapped. Do not modify the status of any exceptions not in S. The data stack is modified as follows.

Data stack
 before    after  
S** : ExceptionSetSpecies  

Binary form

WILL-TRAP

Pop an exception E from the data stack. Push true if E would be trapped in the current context, and false if E would not be trapped.

Data stack
 before    after  
E* : ExceptionSpecies R* : Boolean

Binary form


Computation: Working with exceptions and exception sets

EXCEPTION-CONST L

Push the exception defined at global label L (by an @EXCEPTION declaration) onto the data stack. This is used for structureless exceptions.

Data stack
 before    after  
  E* : ExceptionSpecies

Binary form

EXCEPTION-WRAP L

Push an exception constructed using the exception constructor defined at global label L (by an @EXCEPTION declaration) with the current stack top as an argument onto the data stack.

Data stack
 before    after  
X E* : ExceptionSpecies

If the constructor defined at label L is C, then E is C(X). For example, if X is "orange apple" and the exception constructor defined at label L is domainX, then E is domainX("orange apple").

Binary form

EXCEPTION-UNWRAP L

Get the information associated with an exception.

Data stack
 before    after  
E* : ExceptionSpecies X

Check to see that exception E is either the structureless exception defined at global label L, or is an exception that is constructed using the exception constructor defined at global label L. If it is not, then fail with exception testX.

If E is of the correct kind, then push the information X associated with E. For example, if E is domainX("orange apple") then X is "orange apple". If E is a structureless exception, push ().

Binary form

EXCEPTION-TEST L

Check whether an exception has a given class.

Data stack
 before    after  
E* : ExceptionSpecies R* : Boolean

Check to see that exception E is either the structureless exception defined at global label L, or is an exception that is constructed using the exception constructor defined at global label L. If it is, then push R = true. If not, then push R = false.

Binary form

EXCEPTION-DESCRIPTION

Modify the data stack as follows.

Data stack
 before    after  
E* : ExceptionSpecies D** : List(Char)

D is the description associated with exception E. The description is part of the definition of an exception or exception constructor.

Binary form

EXCEPTION-TO-STRING

Modify the data stack as follows.

Data stack
 before    after  
E* : ExceptionSpecies S* : List(Char)

S is a string that represents exception E. If E is testX, then S is "testX". If E is domainX("orange apple") then S is "domainX(\"orange apple\")"

Binary form

EXCEPTION-SET L

If L is a nonnegative integer then push the exception set defined at global label L. If L is a name then push the standard exception set by that name. The possible names are as follows.

Standard exception sets
allXS The set of all exceptions
shouldTrapXS The set of all exceptions that are very serious, and from which recovery is difficult. This includes memoryX, limitX, domainX(s) and infiniteLoopX.
normallyTrappedXS The set of all exceptions that are initially trapped.
normallyBenignXS The set of all exceptions that are initially not trapped.
terminatingXS The set of all exceptions that indicate termination of a thread. This includes terminateX, detachX and endThreadX.

Data stack
 before    after  
  S** : ExceptionSetSpecies

R is true if exception sets A and B have exactly the same members, and false otherwise.

Binary form

EXCEPTION-SET-EQUAL

Data stack
 before    after  
B** : ExceptionSetSpecies R* : Boolean
A** : ExceptionSetSpecies  

R is true if exception sets A and B have exactly the same members, and false otherwise.

Binary form

EXCEPTION-SET-MEMBER

Data stack
 before    after  
S** : ExceptionSetSpecies R* : Boolean
E* : ExceptionSpecies  

R is true if exception E is a member of exception set S, and is false otherwise.

Binary form

EXCEPTION-SET-COMPLEMENT

Data stack
 before    after  
S** : ExceptionSetSpecies R** : ExceptionSetSpecies

R is the complement of exception set A. It contains all exceptions not in A.

Binary form

EXCEPTION-SET-UNION

Data stack
 before    after  
B** : ExceptionSetSpecies R** : ExceptionSetSpecies
A** : ExceptionSetSpecies  

R is the union of exception sets A and B.

Binary form

EXCEPTION-SET-INTERSECTION

Data stack
 before    after  
B** : ExceptionSetSpecies R** : ExceptionSetSpecies
A** : ExceptionSetSpecies  

R is the intersection of exception sets A and B.

Binary form

EXCEPTION-SET-TO-STRING

Data stack
 before    after  
S** : ExceptionSetSpecies R** : List(Char)

R is a string of the form [a,b,...] where a, b, ... are the constructors of exceptions that are in exception set S.

Binary form


Computation: Backtracking and multiple threads

BACKTRACK L

Split the current thread into two threads. Each thread has a copy of all of the thread-local data structures, and each is initialized the same, with the exception of the instruction counter. The first thread has it instruction counter set to the instruction just after this BACKTRACK instruction. The second thread has its instruction counter set to the instruction after local label L.

A thread is a leaf of a control tree. This instruction splits the leaf by introducing a node above the leaf. The new node is marked as a backtrack node, and has the first and second threads as its children.

Backtrack nodes are handled as follows. As long as there is any active thread in the left subtree of a backtrack node, the right subtree will wait, and will not be performed. If the left subtree ever becomes empty (all threads in it have terminated) then the backtrack node is replaced by its right subtree, and that tree will be allowed to run.

Binary form

FORK L

Split the current thread into two threads. Each thread has a copy of all of the thread-local data structures, and each is initialized the same, with the exception of the instruction counter. The first thread has it instruction counter set to the instruction just after this BACKTRACK instruction. The second thread has its instruction counter set to the instruction after local label L.

A thread is a leaf of a control tree. This instruction splits the leaf by introducing a node above the leaf. The new node is marked as a fork node, and has the first and second threads as its children.

Fork nodes allow their children to run concurrently. Each subtree is updated as the corresponding threads run. If either subtree ever becomes empty, the fork node is removed and replaced by its other child.

Binary form

BEGIN-CUT

Push a cut-mark node just above the current thread's node in the control tree. The cut-mark mode is used in CUT instructions.

Binary form

END-CUT

Remove the closest cut-mark node above the current thread's node from the control tree.

Binary form

CUT

This instruction scans up the control tree from the current thread to the first cut-mark node. At each fork or backtrack node that it encounters, it terminates all threads in the subtree that is not in direction of the current thread. Termination is achieved by the same means as a TERMINATE instruction. A terminate message is sent to each one.

Binary form

WAIT-MILLISECONDS

The data stack is modified as follows.

Data stack
 before    after  
N** : Natural ()*

Cause the current thread to pause for N milliseconds. Other threads that are enabled can run while this thread pauses.

Binary form

PAUSE

Cause the current thread to yield to other threads. This is used if the current thread knows that it cannot make progress until another thread runs, so does not want to do anything for a short time.

Binary form

REPAUSE

This is the same as PAUSE, but it indicates that this thread has made no progress since the last time it paused or repaused. If all threads repause, and there are no external triggers that might release one of the threads, the interpreter will presume that the program has deadlocked.

Binary form

TERMINATE

Modify the data stack as follows.

Data stack
 before    after  
A** : Natural  

Send a terminate request to all threads that have affiliation A in their affiliation sets. When honored, a terminate request causes the thread to fail with exception terminateX. See BEGIN-NOTERMINATE for special circumstances.

Binary form

SUSPEND

Modify the data stack as follows.

Data stack
 before    after  
A** : Natural  

Send a suspend request to all threads that have affiliation A in their affiliation sets. Once suspended, a thread will not run until it is resumed. But see BEGIN-NOSUSPEND and BEGIN-NOTERMINATE for special circumstances.

Binary form

RESUME

Modify the data stack as follows.

Data stack
 before    after  
A** : Natural  

Resume all threads that have affiliation A in their affiliation sets and that have been suspended.

Binary form

SUSPEND-SELF

Cause the current thread to suspend itself. It will not continue until another thread resumes it.

Binary form

BEGIN-NOSUSPEND

Add 1 to the current thread's nosuspend count. When the nosuspend count is positive, the thread cannot be suspended. Any request to suspend it will be remembered, and will be honored when the thread enters a state where it can be suspended.

If a thread receives a suspend request while it cannot be suspended, and receives a resume request before it honors the suspend request, then the suspend request is removed.

Binary form

END-NOSUSPEND

Subtract 1 from the current thread's nosuspend count. If the count was already 0, leave it 0.

If this instruction causes the nosuspend count to become 0, it is possible that a deferred suspend request will be honored now.

Binary form

BEGIN-NOTERMINATE

Add 1 to the current thread's noterminate count. When the noterminate count is positive, the thread cannot be suspended or terminated. Any request to suspend or terminate it will be remembered, and will be honored when the thread enters a state where the request can be honored.

Binary form

END-NOTERMINATE

Subtract 1 from the current thread's noterminate count. If the count was already 0, leave it 0.

If this instruction causes the noterminate count to become 0, it is possible that a deferred suspend or terminate request will be honored now.

Binary form

CHECK-FOR-THREAD

Modify the data stack as follows.

Data stack
 before    after  
A** : Natural R* : Boolean

R is true if there is any other active thread that has affiliation A in its affiliation set.

The active threads are those that are found in the forest of control trees that the interpreter is running. It does include threads waiting at backtrack nodes for other threads to finish. But it does not include any threads that are attached to computations of deferred values.

Binary form

DETACH

Move the current thread's control node, making it a root in the forest of control trees that the interpreter maintains. Replace the old node by a node that will immediately fail with exception detachX.

Binary form

DETACH-AND-CUT

This is the same as DETACH, but it empties the data stack and the call stack. A return from the function that performs this instruction will terminate the thread.

Binary form


Computation: Affiliations

AFFILIATE

Modify the data stack as follows.

Data stack
 before    after  
A** : Natural  

Add affiliation A to the current thread's affiliation set. But refuse to add affiliation 1, since that is managed automatically.

Binary form

UNAFFILIATE

Modify the data stack as follows.

Data stack
 before    after  
A** : Natural  

Remove affiliation A from the current thread's affiliation set. But refuse to remove affiliation 1, since that is managed automatically.

Binary form

CURRENT-AFFILIATIONS

Modify the data stack as follows.

Data stack
 before    after  
  L** : Natural

Push a list of the affiliations of the current thread.

Binary form

INSTALL-AFFILIATIONS

Modify the data stack as follows.

Data stack
 before    after  
L** : Natural  

Install list L as the current affiliations of the current thread. Whether the current thread has affiliation 1 is independent of L. That affiliation is managed automatically.

Binary form


Computation: Locking boxes

LOCK-BOX

Modify the data stack as follows.

Data stack
 before    after  
B* : Box(T) ()

Pop box B from the data stack. If B is a nonshared box, do nothing else. Otherwise, attempt to lock B. The possible outcomes are as follows.

  1. If no thread currently has box B locked, then the current thread locks it, and continues. Box B is added to the locked-box list.

  2. If the current thread already has box B locked, then the lock count for this thread for box B is incremented. (Another copy of B is added to the locked box list.) A thread can have an arbitrarily large lock count for any given box.

  3. If some thread has this box locked, but the current thread does not have it locked, then this thread waits until box B is unlocked, at which time it can continue, and it completes this instruction.

When B is a computed box, this instruction performs an application of the locking function of the computed box. It pushes a new frame on the call stack, and continues with that new frame. The value returned by that function is on the stack when the current function continues with the next instruction.

Binary form

UNLOCK-BOX

Modify the data stack as follows.

Data stack
 before    after  
B* : Box(T) ()

Pop box B from the data stack. Perform the following action.

  1. If B is a nonshared box, or if B does not occur in this thread's list of locked boxes, then do nothing.

  2. If the current thread has box B in its list of locked boxes, then remove one of the copies of B from that list. If this thread's lock count for B becomes 0, and no other threads have B locked, and if any thread has attempted to lock B, then allow one of those threads to lock B.

Selection of a thread to let run is done in a fair manner in the sense that no thread that is trying to lock the box will wait indefinitely while other threads are repeatedly given the lock. Any given thread will eventually be chosen.

When B is a computed box, this instruction performs an application of the unlocking function of the computed box. It pushes a new frame on the call stack, and continues with that new frame. The value returned by that function is on the stack when the current function continues with the next instruction.

Binary form

UNLOCK-BOX-COMPLETELY

This is similar to UNLOCK-BOX, the only difference being that it removes all copies of B from the current thread's list of locked boxes.

Binary form

UNLOCK-ALL

Data stack
 before    after  
()  

Make the current thread's list of locked boxes be empty. This has the same effect as performing UNLOCK instructions until all of the locks are removed.

Binary form

LOCKED-BOX

Data stack
 before    after  
B* : Box(T) R* : Boolean

R is true if box B is in the current thread's list of locked boxes at least once.

Binary form


Computation: System calls and related functions

OPEN-OUTFILE

Open a file and push it onto the data stack. Modify the data stack as follows.

Data stack
 before    after  
M** : List(Natural) F* : SysOutfile
path** : List(Char)  

Path is the path name of the file to open, relative to the current thread's working directory. F is a SysOutfile that can be used to write to the listed file. List M indicates mode information.

If it is not possible to open the file then this instruction fails with exception noFileX(path). In the special case where the open failed because path is a directory, the exception is fileTypeX(path).

Binary form

CLOSE-FILE

Close a SysOutfile object. Modify the data stack as follows.

Data stack
 before    after  
F* : SysOutfile  

Close file F. Any subseqent attempts to write to F will fail. Closing a file that is already closed has no effect.

Binary form

PRINT-CHAR

Modify the data stack as follows.

Data stack
 before    after  
c* : Char  
F* : SysOutfile  

Print character c on file F.

If file F has been closed, this instruction fails with exception closedFileX.

Binary form

PRINT

Modify the data stack as follows.

Data stack
 before    after  
L**** : List(List(Char))  
F* : SysOutfile  

Print all of the strings in list L to file F, in the order in which they occur in L.

If file F has been closed, this instruction fails with exception closedFileX.

Binary form

FLUSH-FILE

Modify the data stack as follows.

Data stack
 before    after  
F* : SysOutfile  

Output is buffered. Flush the buffer of file F.

Binary form

OUTFILE-TO-STRING

Produce a string that describes a SysOutfile. Modify the data stack as follows.

Data stack
 before    after  
F* : SysOutfile S* : List(Char)

F is a SysOutfile object, and S is a string that describes it, such as "outfile(name)".

Binary form

READ-FILE

Modify the data stack as follows.

Data stack
 before    after  
M** : List(Natural) R : List(Char)
path** : List(Char)  

Open file path for reading. The path is relative to the current thread's working directory. Push a string R that is the contents of the file.

M is a list of modes.

The file is not actually read immediately. Reading only begins when part of the file is examined. Only part of the file is read at a time, with the remainder being lazy. More will be read as it is used. Indexing into the file string using SUBSCRIPT or SUBLIST might cause a seek to be done on the file to find a position to continue reading.

If it is not possible to open this file for reading, this instruction fails with exception noFileX(path). In the special case where path is a directory, it fails with exception fileTypeX(path).

Binary form

CHDIR

Change the current directory. Modify the data stack as follows.

Data stack
 before    after  
S** : List(Char)  

S is the path name of a directory to remove, relative to the current thread's working directory. Make S be the working directory of the current thread. This modifies the content of the cwd box, and also checks that it is possible to select S as the working directory.

This instruction fails with exception fileTypeX(S) if S is not a directory, and with exception noFileX(S) if it was not possible to select S as the current working directory for some other reason.

Binary form

RENAME-FILE

Rename a system file. Modify the data stack as follows.

Data stack
 before    after  
R** : List(Char)  
S** : List(Char)  

R and S must be path names relative to the current directory. Rename file S to R. Fail with exception noFileX(S) if this cannot be done, either because S does not exist or because this process does not have permission to do the renaming.

Binary form

UNLINK-FILE

Remove a system file. Modify the data stack as follows.

Data stack
 before    after  
S** : List(Char)  

S is the path name of a file, relative to the current thread's working directory. Unlink system file S from the file system, if possible. Fail with exception noFileX(S) if this cannot be done, either because S does not exist or because this process does not have permission to do the unlink.

Binary form

RMDIR

Remove a system directory. Modify the data stack as follows.

Data stack
 before    after  
S** : List(Char)  

S is the path name of a directory to remove, relative to the current thread's working directory. Remove system directory S from the file system, if possible. Fail with exception noFileX(S) if this cannot be done, or with exception fileTypeX(S) if S is not a directory.

This instruction will only remove a directory if the directory is empty. It fails if the directory is not empty.

Binary form

MKDIR

Create a system directory. Modify the data stack as follows.

Data stack
 before    after  
S** : List(Char)  

S is the path name of a directory to create, relative to the current thread's working directory. Create system directory S from the file system, if possible. Fail with exception noFileX(S) if this cannot be done.

Binary form

DIRLIST

Read a directory. Modify the data stack as follows.

Data stack
 before    after  
S** : List(Char) L** : List(List(Char))

S is the path name of a directory, relative to the current thread's working directory. L is a list of the names of all files in directory S. The names are not full path names, but just the names local to this directory, but excludes "." and "..". Fail with exception noFileX(S) if this cannot be done, or with exception fileTypeX(S) if S is not a directory.

Binary form

SYM-LINK

Create a symbolic link. Modify the data stack as follows.

Data stack
 before    after  
F** : List(Char)  
S** : List(Char)  

F and S are path names relative to the current thread's working directory. Create a symbolic link called S that refers to existing file or directory F. Fail with exception noFileX(S) if the link could not be created.

Binary form

READ-LINK

Read a symbolic link. Modify the data stack as follows.

Data stack
 before    after  
S** : List(Char) A** : List(Char)

S is a path name relative to the current thread's working directory. A is the file or directory to which symbolic link S refers. Fail with exception noFileX(S) if S does not exist and fileTypeX(S) if S is not a symbolic link.

Binary form

STAT-FILE

Get information about a file. Modify the data stack as follows.

Data stack
 before    after  
S** : List(Char) R** : (Natural, (Boolean, (Natural, (Natural, (Boolean, (Boolean, Boolean)), (Natural, Natural)))))

S is a path name relative to the current thread's working directory. R is (status, is_lnk, size, mtime, (read-perm, write-perm, exec-perm), owner, group) where

Binary form

GET-ENV

Get the value of an environment variable. Modify the data stack as follows.

Data stack
 before    after  
S** : List(Char) V** : List(Char)

S is the name of an environment variable. V is the value associated with that environment variable in the system environment. This instruction fails with exception notFoundX if there is no such environment variable.

Binary form

PUT-ENV

Modify the value of an environment variable. Modify the data stack as follows.

Data stack
 before    after  
n** : Natural  
binding** : List(Char)

String binding must be of the form "name=val", and n must be at least as large as the length of binding. Modify the system environment so that variable name has value val. If there is no current binding of name, one is added.

Binary form

OS-ENV

Get the entire system environment. Modify the data stack as follows.

Data stack
 before    after  
  L** : List(List(Char), List(Char))

L is a list of pairs [(name1, val1), (name2, val2), ...]. indicating that name1 is bound to val1, etc. in system environment.

Binary form

MILLISECONDS-NOW

Get the current time. Modify the data stack as follows.

Data stack
 before    after  
  N* : Natural

N is a current time as a number of milliseconds since 0:00 GMT Jan. 1 1970.

Binary form

FILE-REF-STRING

Back up a string on disk. Modify the data stack as follows.

Data stack
 before    after  
info : (List(Char), (List(Char), (Natural, (Natural, Box(Boolean))))) S : List(Char)

This instruction is used to cache a string in a file so that the string can be removed from memory and recovered later from the file.

Info is a tuple (val,(fname,(offset, (mode, (ready))))) where is a shared box that is used to tell when the file is ready to read. If ready is not a nonshared box, then this instruction fails with exception domainX("need shared box for file-ref-string").
val is a string
fname is a file path name (a string)
offset is an integer offset in file fname
mode is an open mode. It is 0 for opening in text mode and 4 for opening in binary mode.
ready

Push, in place of info, a value S that is the same as val, but that indicates that it can be recovered from file fname by opening it with the given mode and seeking to the given offset.

Warning. This instruction does not write any information into file fname. It does not attempt to open this file at all. It is the responsibility of some other part of the program to write the file. Box ready is used to tell when the writing has been completed. If ready contains false or is empty, the file has not been written, and cannot be used yet. When the program is done writing the file, it sets ready to hold true to indicate that the file is ready to be read, when needed.

When the file is ready, the garbage collector might remove S from memory, preferring to read it back from the file if necessary later.

Info is evaluated up to the point where its parts (val, fname, offset, mode, ready) are available. All parts except val are evaluated. String val is not evaluated by this instruction.

Binary form

REFERENCED-FILES

Modify the data stack as follows.

Data stack
 before    after  
  L** : List(List(Char))

L is a list of all files that are currently being read by the interpreter. Each file name is a full path name. These files might be open for reading, and might be open in a lazy way where they will be opened later if information from the file is needed.

Binary form

PROCESS-NUM

Get the interpreter's process number. Modify the data stack as follows.

Data stack
 before    after  
  N* : Natural

N is the process number of the interpreter.

Binary form

SIGNAL-PROCESS

Signal a process. Modify the data stack as follows.

Data stack
 before    after  
S* : Natural  
N* : Natural  

N is the process id number of a system process, and S is a signal number. Send signal S to process N.

Binary form

CREATE-PROCESS

Signal a process. Modify the data stack as follows.

Data stack
 before    after  
opt* : Natural R : ((), List(Char), List(Char), List(Char), Natural, Natural)
L** : List(List(Char))  

L is a list of strings representing a command to the system, as an argument vector. The first string in list L is the command to run. It is a path name, but the command to run is found using the system PATH variable.

Create a new process and run command L in that process. This instruction does not wait for the other process to terminate. It returns as soon as the other process has been created.

Opt is a list of options for running the command. Each member of opt has one fo the following forms. (S:n) indicates a tagged value with integer tag n.

Options for CREATE-PROCESS
(S:0) Run the command with its standard input containing string S.
(S:1) Run the command with its standard input drawn from the system file whose name is S. S is a string that is a path name relative to the current thread's working directory.
(S:2) Run the command with its standard output redirected to the system file called S. S is a string that is a path name relative to the current thread's working directory. If this file already exists, truncate (empty) it before writing.
(S:3) Run the command with its standard output redirected to the system file called S. S is a string that is a path name relative to the current thread's working directory. If this file already exists, append the command output to the end of what is currently in file S.
4 Merge the standard error output into the standard output.
5 Ignore the both the standard error and the standard output.

If neither option (S:0) nor (S:1) is given, then the standard input of the new process will be empty. If more than one of (S:0) and (S:1) is given, the first one in list opt is used.

The result R is a tuple (interact, out, err, rest, status, pid) where the components are as follows.

Results of CREATE-PROCESS
interact

This is an item that MUST be evaluated in order to interact with the new process. It is the program's responsibility to force evaluation of it. Failure to evaluate this will cause undetermined results, including possibly failure of the new process to finish.

When interact is finished evaluating it produces () as its result.

out If none of the options (S:2), (S:3) or 5 are present in opt, then out is a lazy string that contains what is written to the standard output by the other process. As more information is written by the process, it shows up in this string. The string is terminated by an unknown until the process has finished, so that an attempt to read beyond the end of what has been written will cause a thread to wait.

If options (S:2) or (S:3) are given, then the first one of those in the option list is used. In this case, out is an empty string, since the output was redirected to a file.

If neither (S:2) nor (S:3) is in opt, but opt contains 5, then out is an empty string. In this case, the standard output is ignored.

err

If neither of options 4 or 5 are in opt, then err is what the command process wrote to its standard error output. Like out, it is ended by an unknown until the process terminates.

If option 5 is present, then the standard error is ignored, and err is an empty string.

If option 4 is in opt, but option 5 is not in opt, then the standard error output is merged into the standard output, and err is an empty string.

rest If option (S:0) occurs (before any (S:1) option) then rest is an unbound unknown when this instruction returns. When the new process terminates, that unknown is bound to the part of string S that the command process did not read.

If option (S:0) is not in opt or is preceded by (S:1), then rest is an empty string.

status Status is initially an unbound unknown. When the new process terminates, this unknown is bound to the termination status (an integer) of the process.
pid Pid is the process id number of the command process.

If the command could not be created then this instruction fails with exception systemX(info) where info is a string that describes the problem. If there is a problem opening the files for standard input or standard output, then this instruction fails with exception noFileX(name), where name indicates the file that could not be opened.

Binary form


Computation: Sockets and network

OPEN-SOCKET

Create a new socket. Modify the data stack as follows.

Data stack
 before    after  
(P,M)** : (Natural, [Natural]) sock* : Socket
I** : Natural  

I is an IP address (a 32 bit integer, in network byte order), P is a port number and M is a list of modes. Push a socket that is connected to port P on host I, opened with mode M.

Fail with exception networkX if the connection fails.

Binary form

CLOSE-SOCKET

Close an open socket. Modify the data stack as follows.

Data stack
 before    after  
sock* : Socket  

Close socket sock. Any subseqent attempts to write to F will fail. Closing a socket that is already closed has no effect.

This instruction is the same as CLOSE-OUTFILE.

Binary form

READ-SOCKET-BLOCK

Modify the data stack as follows.

Data stack
 before    after  
sock* : Socket S** : List(Char)

Pop sock, which must be an open socket. Read some characters from sock and push them onto the stack, as a string S. If there is any data available, then S will be a nonempty string. Its length is not determined. If an end-of-file is encountered immediately, fail with exception listExhaustedX.

If there is no information available from socket sock, then this instruction causes the thread that performed it to block until some information is available.

Fail with exception networkX if the read fails because of a network problem.

Binary form

READ-SOCKET-NOBLOCK

Modify the data stack as follows.

Data stack
 before    after  
sock* : Socket S** : List(Char)

Pop sock, which must be an open socket. Read some characters from sock and push them onto the stack, as a string S. If there is any data available, then S will be a nonempty string. Its length is not determined. If an end-of-file is encountered immediately, fail with exception listExhaustedX. If there is no information available immediately, but no end-of-file has been encountered either, then S is an empty string. A later read might yield more data.

Fail with exception networkX if the read fails because of a network problem.

Binary form

WRITE-SOCKET-BLOCK

Modify the data stack as follows.

Data stack
 before    after  
S**** : List(Char) R : List(Char)
sock* : Socket  

Write a (not necessarily proper) prefix of string S to socket sock. Typically, that will be all of S, but it might not be. R is the suffix of S that was not written. For example, if S is "abcdefghi" and this instruction chooses only to write the first 5 characters of S to the socket, then R will be "fghi". If all of S is written then R is an empty string.

This instruction will write at least one character to the socket. If the socket is not ready to accept any more characters, then this instruction causes the thread that performed it to block until it can perform a write, and write at least one character to the socket.

Fail with exception networkX if the write fails because of a network problem.

Binary form

WRITE-SOCKET-NOBLOCK

This is similar to WRITE-SOCKET-BLOCK, but if it the socket is not ready to accept any characters then no characters are written, and R = S.

Binary form

SOCKET-NUMBER

Modify the data stack as follows.

Data stack
 before    after  
sock* : Socket N* : Natural

As sockets are created they are numbered, and each gets a different number. N is the number of socket sock.

Binary form

IP-ADDRESS

Modify the data stack as follows.

Data stack
 before    after  
S** : List(Char) I* : Natural

This instruction performs a DNS lookup. If S name of an internet host then I is its IP address, as a 32 bit integer in network byte order.

If the host does not exist, then this instruction fails with exception hostNameX(S). If there is a problem performing the lookup then this instruction fails with exception networkX.

Binary form

IP-NAME

Modify the data stack as follows.

Data stack
 before    after  
I* : Natural S** : List(Char)

This instruction performs a reverse DNS lookup. I is an IP address, as a 32 bit integer in network byte order. S is a corresponding host name.

If the host does not exist or information on it is not available, then this instruction fails with exception hostNameX(I') where I' is a string that describes I. If there is a problem performing the lookup then this instruction fails with exception networkX.

Binary form


Computation: Miscellaneous

FINALIZER

Modify the data stack as follows.

Data stack
 before    after  
B* : Box(Boolean -> ())  

B must be a shared box. This instruction registers B with the garbage collector. When box B is collected by the garbage collector, the following is done.

  1. If box B is empty the no additional processing is done. The garbage collector destroys the box.

  2. If box B is being collected during a normal garbage collection, and B contains function F, then a new detached thread is created that runs F(true). Box B is not destroyed, but it is removed from the registered boxes before running F.

  3. If box B is being collected during clean up at the end of the program, and B contains function F, then a new detached thread is created that runs F(false). Box B is not destroyed, but it is removed from the registered boxes before running F. It is possible for F to register new boxes with the garbage collector, causing more rounds of garbage collection to be performed for clean up. The interpreter will only perform a few phases of this before it stops the program, even though there remain registered boxes that have not had their functions run.

Binary form

LINE n

Indicate that the code that follows this instruction is from source line n.

Example

Binary form

NAME L

L should be a global label that occurs prior to the current instruction's location, and that labels an @ID declaration. Indicate that the section of code to follow should be called by the name defined at that @ID declaration. This is used for debugging and for naming functions.

Example

Binary form

SNAME L

L should be a global label that occurs prior to the current instruction's location, and that labels a @STRING declaration. Indicate that the section of code to follow should be called by the name defined at that @STRING declaration. This is used for debugging and for naming functions. The string at label L must not contain any null characters.

Example

Binary form

BEGIN-VIEW

Add 1 to the view flag. See LAZY-TO-STRING, below.

Binary form

END-VIEW

Subtract 1 from the view flag, but do not change it if it was 0.

Binary form

LAZY-TO-STRING

Modify the data stack as follows.

Data stack
 before    after  
X S** : List(Char)

If the view flag is nonzero and X is a promise or an unknown then this instruction pushes S as shown. S is a string that describes this promise or unknown.

If the view flag is 0 or X does not have the correct form, then this instruction fails with exception testX.

Binary form

PRIM-TRACE

Modify the data stack as follows.

Data stack
 before    after  
N* : Natural  

Set the interpreter's trace flags. N is an OR of the following flags.

Modes for PRIM-TRACE
 1  Trace each instruction as it is executed.
 2  Show the environment at each instruction.
 4  Trace input/output operations and a few extra things.
 8  Trace searching of global definition tables.
 16  Show the type stack with each instruction.
 32  Show the trap set with each instruction.
 128  Show control tree with each instruction. The tree is shown upwards from the current thread leaf.

The trace flags are set to exactly the values indicated by N, regardless of their former values. Traces are printed to the trace file. See options for the interpreter for controlling the trace file.

Binary form

CONTINUATION-NAME

Modify the data stack as follows.

Data stack
 before    after  
  S* : List(Char)

S is the name of the function to which this function will return when it is done. (Typically, this is also the name of the function that called this function. But if tail-recursion improvement has been used, that might not be the case.)

If this function is at the bottom of the call stack then S is "(nobody)"

Binary form

RAW-SHOW

Modify the data stack as follows.

Data stack
 before    after  
X  
F* : SysOutfile  

Print a description of the internal representation of X onto file F. This is only useful for low-level debugging.

Binary form

SHOW-ENV

Modify the data stack as follows.

Data stack
 before    after  
F* : SysOutfile  

Show the environment of the current function, including nonlocal bindings, but excluding the static environment, on file F.

If the interpreter is being run in normal mode, bindings that have been marked as no longer needed will not be shown because they have been destroyed. If the interpreter is being run in debug mode (-t), all of the bindings should be available.

Binary form

SHOW-CONFIG

Modify the data stack as follows.

Data stack
 before    after  
F* : SysOutfile  

Dump the entire current configuration onto file F.

Binary form

PROFILE

Modify the data stack as follows.

Data stack
 before    after  
X* : Boolean  

The interpreter can keep elementary profile information about how many instructions are performed by each function. If X is true then this instruction turn on profiling. If X is false then profiling is turned off.

Binary form

SET-STACK-LIMIT

Modify the data stack as follows.

Data stack
 before    after  
N* : Natural  

The interpreter keeps a soft limit on the depth of the call stack of any single thread. If the stack becomes deeper than this limit, the interpreter asks the user whether to continue. This instruction sets the stack limit to N.

Binary form

GET-STACK-LIMIT

Modify the data stack as follows.

Data stack
 before    after  
  N* : Natural

N is the interpreter's current soft limit on the depth of the call stack.

Binary form

GET-STACK-DEPTH

Modify the data stack as follows.

Data stack
 before    after  
  N* : Natural

N is the current depth of the call stack for the current thread. The call stack depth does not include the function that is running. It only includes those that are in the stack waiting for a return.

Binary form

SET-HEAP-LIMIT

Modify the data stack as follows.

Data stack
 before    after  
N* : Natural  

The interpreter keeps a soft limit on the amount of data in garbage-collected memory (the heap). If the heap becomes deeper than this limit, the interpreter asks the user whether to continue. This instruction sets the heap limit to N kilobytes.

Binary form

GET-HEAP-LIMIT

Modify the data stack as follows.

Data stack
 before    after  
  N* : Natural

N is the interpreter's current soft limit on the size of the heap, in kilobytes.

Binary form

SET-THREAD-LIMIT

Modify the data stack as follows.

Data stack
 before    after  
N* : Natural  

The interpreter keeps a soft limit on the number of active threads. This instruction sets that limit to N.

Binary form

GET-THREAD-LIMIT

Modify the data stack as follows.

Data stack
 before    after  
  N* : Natural

N is the interpreter's current soft limit on the number of threads.

Binary form

SET-LAZY-LIMIT

Modify the data stack as follows.

Data stack
 before    after  
N* : Natural  

The interpreter keeps a soft limit on the depth of deferred evaluation (evaluating a promise while evaluating a promise while evaluating another promise, ...). This instruction sets the lazy evaluation depth to N.

Binary form

GET-LAZY-LIMIT

Modify the data stack as follows.

Data stack
 before    after  
  N* : Natural

N is the interpreter's current soft limit on the depth of deferred evaluation.

Binary form

GARBAGE-COLLECT

Request a garbage collection now. You probably do not want to do this.

Data stack
 before    after  
()  

Binary form

SUPPRESS-COMPACTIFY

The garbage collector can move things around. This causes box ranks to change. Pop Xfrom the data stack. If X is true, then turn off compactification. If X is false then run compactification on. If you leave compactification off for a long time you will get serious fragmentation problems.

Data stack
 before    after  
X* : Boolean  

Binary form


Specifying the size of an environment

When indicating the number of environment entries needed, an index in the following table is used. Use an index that has an associated size that is at least as large as is needed.

Environment sizes
Index Maximum number of bindings
0 0
1 4
2 8
3 16
4 32
5 64
6 128
7 255


Standard exceptions

Some exceptions, such as subscriptX, are simple values. Some have structure, so that they can supply more information. For example, domainX(s) has a string s associated with it. All of the standard exceptions that have structure are accompanied by strings.

The built-in exceptions are as follows. Each has a number indicated in the table, a brief description of its intended meaning and an indication of whether it is marked as trapped initially.

Standard exceptions
Number Exception Indication Trap
 0  endThreadX A thread terminated itself no
 1  detachX A thread detached itself no
 2  terminateX A thread was terminated by another thread no
 3  testX A test failed no
 4  conversionX A conversion could not be done no
 5  sizeX Size mismatch yes
 6  speciesX There was a run-time species mismatch no
 7  notFoundX A sought thing was not found no
 8  listExhaustedX Attempt to read a value from an empty string no
 9  memoryX Ran out of memory yes
 10  limitX A compiled-in limit, such as path name length, was exceeded yes
 11  emptyBoxX Attempt to get the content of an empty box yes
 12  emptyListX Attempt to get the head or tail of an empty list yes
 13  bindUnknownX Cannot bind an unknown no
 14  subscriptX Subscript out of bounds yes
 15  domainX(s) A function was given a parameter that it cannot handle yes
 16  noDefX(s) A (name,species) pair has no definition in the global definition table no
 17  noCaseX No case was available to handle a computation yes
 18  noMatchCaseX(s) No case was found to handle a definition no
 19  infiniteLoopX There was an infinite loop during lazy evaluation yes
 20  noFileX(s) A file does not exist or has incorrect permission no
 21  fileTypeX(s) A file has the wrong type no
 22  cannotSeekX A seek could not be done on a file yes
 23  tooManyFilesX Too many open files yes
 24  closedFileX Attempt to write to a closed file yes
 25  interruptX The interpreter was interrupted and the thread terminated no
 26  systemX(s) An error occurred creating a process no
 27  networkX A network error occurred no
 28  hostNameX(s) Unknown host name no


Forcing evaluation

Some of the instructions force evaluation of promises, and some do not. The following labels on parameters indicate evaluation. When they occur on an input to an instruction (in the before stack) they indicate evalation that the instruction will perform, if necessary. When these occur on the output of an instruction (in the after column) they indicate a level of evaluation that is guaranteed to have been done already.

It is important to distinguish partial evaluation from full evaluation. A list can be partially evaluated (indicated by *) by discovering that it has a given head and a given tail. The head and tail might themselves still be promises. If a list is fully evaluated, the entire list structure is determined, and each member of the list is evaluated.

For simple values (including untagged numbers, boxes, functions and SysOutfiles) there is no difference between partial evaluation and full evaluation. There are no parts to be left as promises. Full evaluation never evaluates the content of a box. It stops at the box itself. Species as values are always either unevaluated or fully evaluated. They can never have unevaluated parts. Exception sets are similarly always either unevaluated or fully evaluated.

Forcing notes
Mark Meaning
 *  Forces evaluation of a promise to the point where it is no longer a promise, but might not evaluate further promises that lie beneath the top level structure.
 **  Forces evaluation of promises until no more promises are found by going into pairs and lists. Does not attempt to evaluate the content of a box.
 ***  Evaluates list structure to as deep a level as necessary to compute its result, but does not evaluate list members.
 ****  Evaluation not determined. Might be lazy, and might evaluate structure needed for its result.