# Modules

A module is a collection of declarations of constants, types, variables, and procedures, together with a sequence of statements for the purpose of assigning initial values to the variables. A module constitutes a text that is compilable as a unit.

      Module     = MODULE ident ";" [ImportList]
                   DeclarationSequence
                   [ BEGIN StatementSequence ]
                   END ident ".".
      ImportList = IMPORT Import {"," Import} ";".
      Import     = [ident ":="] ident.

The import list specifies the names of the imported modules. If a module A is imported by a module M and A exports an identifier x, then x is referred to as A.x within M. If A is imported as B := A, the object x is referenced as B.x. This allows short alias names in qualified identifiers. A module must not import itself. Identifiers that are to be exported (i.e. that are to be visible in client modules) must be marked by an export mark in their declaration (see section Declarations and scope rules).

The statement sequence following the symbol BEGIN is executed when the module is added to a system (loaded), which is done after the imported modules have been loaded. It follows that cyclic import of modules is illegal. Individual (parameterless and exported) procedures can be activated from the system, and these procedures serve as commands.

    MODULE Trees;
    (* exports:
      Tree, Node, Insert, Search, Write, NewTree
    *)
    (* exports read-only: Node.name *)
    IMPORT Texts, Oberon;
    TYPE
      Tree* = POINTER TO Node;
      Node* = RECORD
        name-: POINTER TO ARRAY OF CHAR;
        left, right: Tree
      END;

    VAR w: Texts.Writer;

    PROCEDURE (t: Tree) Insert* (name: ARRAY OF CHAR);
      VAR p, father: Tree;
    BEGIN
      p := t;
      REPEAT father := p;
        IF name = p.name^ THEN RETURN END;
        IF name < p.name^ THEN p := p.left
        ELSE p := p.right
        END
      UNTIL p = NIL;
      NEW(p); p.left := NIL; p.right := NIL;
      NEW(p.name,LEN(name)+1);
      COPY(name,p.name^);
      IF name < father.name^ THEN father.left := p
      ELSE father.right := p
      END;
    END Insert;

    PROCEDURE (t: Tree) Search* (name: ARRAY OF CHAR): Tree;
      VAR p: Tree;
    BEGIN
      p := t;
      WHILE (p # NIL) & (name # p.name^) DO
        IF name = p.name^ THEN p := p.left
        ELSE p := p.right
        END
      END;
      RETURN p
    END Search;

    PROCEDURE (t: Tree) Write*;
    BEGIN
      IF t.left # NIL THEN t.left.Write END;
      Texts.WriteString(w, t.name^);
      Texts.WriteLn(w);
      Texts.Append(Oberon.Log, w.buf);
      IF t.right # NIL THEN t.right.Write END
    END Write;

    PROCEDURE NewTree* (): Tree;
      VAR t: Tree;
    BEGIN
      NEW(t); NEW(t.name, 1);
      t.name[0] := 0X;
      t.left := NIL; t.right := NIL;
      RETURN t
    END NewTree;

    BEGIN
      Texts.OpenWriter(w)
    END Trees.