13 Modules

13.1 Using a module

Syntax
import = "use" NAME [ "as" NAME ] ;

(1) One source is one module. The name the host gave when loading the source is the module’s name (pnx uses the file name without .pnx). Standard modules and host modules (13.3) are modules too.

(2) use MODULE opens that module in this source; from then on its parts are written as the path MODULE.NAME. use MODULE as ALIAS makes the same module be written ALIAS.NAME. Only core words and what this source declares are written as bare names, and the words of the modules a search order names (13.5).

(3) A module that is used shall exist already: a standard module, a module the host registered, or a source loaded earlier. When pnx meets use NAME it first loads NAME.pnx from beside the program file.

13-use.pnx

use io
use str
use geometry
200 50 geometry.area str.to_str io.println
geometry.unit str.to_str io.println
array corners point 2                       rem an exported record is used by its name
3 0 corners idx to point.x
0 corners idx point.x str.to_str io.println

Output

$ pnx 13-use.pnx
100
10
3

13-use-as.pnx

use io
use str
use geometry as g
200 50 g.area str.to_str io.println

Output

$ pnx 13-use-as.pnx
100
Constraints

(4) Using a module that does not exist is refused.

13-unknown-module.pnx

use geometrie

Refused

$ pnx 13-unknown-module.pnx
13-unknown-module.pnx:1:5: no module of this name is registered or loaded

(5) A word of a module written as a bare name is refused, unless a search order names that module (13.5); so is a path into a module that was not opened.

13-bare-name.pnx

use geometry
200 50 area drop

Refused

$ pnx 13-bare-name.pnx
13-bare-name.pnx:2:8: this name is not declared before this place

13-no-use.pnx

use io
5 str.to_str io.println

Refused

$ pnx 13-no-use.pnx
13-no-use.pnx:2:3: this path names neither a module in use nor a record

13.2 Exports

(1) Another source can use only what was declared or defined with export. Words, constants and globals are written MODULE.NAME (an exported global is stored with set MODULE.NAME); exported records and types and the row types of tables are written by their name alone.

(2) The module geometry below is the one the examples of 13.1 use. square is not exported.

geometry.pnx

rem A module: only what is marked export is seen by a source that uses it.
export const unit 10
export record point
  x int
  y int
end
word square (n int gives int) n n mul end
export word area (w int, h int gives int) w h mul unit square div end
Constraints

(3) Using what is not exported is refused.

13-not-exported.pnx

use geometry
4 geometry.square drop

Refused

$ pnx 13-not-exported.pnx
13-not-exported.pnx:2:3: the module exports nothing of this name

13.3 Standard modules and host modules

(1) The standard modules come with the processor and are part of the language: str fmt hash encode bytes ptn rex json csv (clause 16). They are seen only after use.

(2) A host module is a set of words the host registered. A module the host did not register does not exist. Everything a script can do outside itself (files, clocks, the environment) is a word the host registered. pnx registers the standard host modules io file clock random env (clause 17).

(3) err is a set of constants written as paths without use (11.1).

13.4 Data load

Syntax
data-source = { data-item } ;
data-item   = [ "export" ] ( [ "bound" ] bindable | "const" NAME literal
              | "list" NAME type size | "queue" NAME type size | "pool" NAME NAME size
              | "record" NAME { field | "big_endian" } "end" | "type" NAME base
              | "index" NAME NAME PATH )
            | "forward" ( "array" | "list" | "pool" ) NAME
            | row-item | assign-item
            | data-value [ data-value ] "set" NAME              (* a global, or a cell *)
            | data-value NAME "to" PATH ;                      (* a field of a named row *)
data-value  = literal | NAME ;                      (* NAME: a const or a row name *)

(1) A source the host reads by data load accepts declarations and values only. Word definitions, calls, use, extern, test, control, blocks and cat are refused. Such a source therefore cannot run any code. It is for reading settings, data and other text that is not trusted.

(2) A value is stored with value set NAME, a cell with value index set NAME ("10.0.0.1" 0 set allow) and a field of a named row with value ROW to RECORD.FIELD, as in code (8.8, 9.4). Everything a data source declares counts as exported.

13-data-load.c

#include "pinax.h"
#include <stdio.h>
#include <string.h>

static pinax_err load(pinax_state *st, const char *name, const char *text) {
    pinax_err err = pinax_load(st, name, (pinax_str){(const unsigned char *)text, strlen(text)}, PINAX_LOAD_DATA);
    if (err != PINAX_OK) {
        pinax_str why = pinax_error_text(st);
        printf("%s refused: %.*s\n", name, (int)why.len, (const char *)why.ptr);
    }
    return err;
}

int main(void) {
    static unsigned char block[1 << 20];
    pinax_config config = {.struct_size = sizeof config};
    pinax_state *st;
    if (pinax_open((pinax_mem){block, sizeof block}, &config, &st) != PINAX_OK)
        return 1;

    /* A settings file: declarations and values only. */
    if (load(st, "settings",
             "global port int\n"
             "global name str(16)\n"
             "array allow str(16) 4\n"
             "8080 set port\n"
             "\"edge\" set name\n"
             "assign allow (\"10.0.0.1\", \"10.0.0.2\")\n") != PINAX_OK)
        return 1;
    pinax_global g;
    if (pinax_global_find(st, "port", &g) != PINAX_OK)
        return 1;
    printf("port = %lld\n", (long long)*(const int64_t *)g.ptr);

    /* The same mode refuses code: nothing in such a file can run. */
    load(st, "evil", "word boom () 1 0 div drop end\n");
    load(st, "evil2", "global n int\n1 2 add set n\n");
    pinax_close(st);
    return 0;
}

Output

$ ./13-data-load
port = 8080
evil refused: a data source defines no words and uses no modules
evil2 refused: a data source calls no words; only literals, const names and stores
Diagnostics
ConditionMessage
A module that does not existno module of this name is registered or loaded
A path into a module not opened, or no recordthis path names neither a module in use nor a record
A name not exportedthe module exports nothing of this name
A definition or use in a data loada data source defines no words and uses no modules
A call in a data loada data source calls no words; only literals, const names and stores

13.5 The search order

Syntax
search = "search" ( "(" [ NAME { "," NAME } ] ")" | "none" ) ;

(1) search (io, str) gives the search order: the modules in which a bare name is looked for. Each module named is opened as by use (13.1 (2), (3)); pnx loads a file module beside the program first, as for use. search () and search none empty the order. Without a search order, nothing is looked for in a module.

(2) A bare name in code is looked for in this order, and the first that has it is taken: the locals and parameters; what this source (or session) declares; the core words; then the modules of the search order, left to right. So a name of the source and a core word keep their meaning whatever the order holds, and a module added to it cannot change code that compiled before. A word of a module named like a core word (str.len beside len) is written with its path. A path is read as before.

13-search.pnx

use io
use str
search (io, str)
"pinax" upper println
word shout (s str) cat (s upper, "!") println end
"hello" shout
"abc" str.len 3 eq if "three bytes" println end

Output

$ pnx 13-search.pnx
PINAX
HELLO!
three bytes

13-search-core.pnx

search (str)
word size (s str gives int) s len end

Refused

$ pnx 13-search-core.pnx
13-search-core.pnx:2:31: this word takes the name of an array, list, queue or buffer; of a str it is str.len

(3) A search order stands at the top level of a source or of a session line, as often as needed. Each one replaces the order from there to the end of the source; a session keeps it for the lines after, until the next one. A word takes what its names found when it was compiled.

(4) A name reached through the search order does not count for the rule against hiding names (9.5): a local may have the name of a word of a module in the order, and inside that word the local is meant.

Constraints

(5) A search order inside a definition or a block, one that names a module twice or more than 16 modules, and one that names a module that does not exist are refused.

Diagnostics
ConditionMessage
search inside a definitionsearch stands at the top level, outside definitions and blocks
No parenthesessearch is followed by modules in parentheses: search (io, str)
A module named twicethis module is named twice in the search order
More than 16a search order names at most 16 modules