13 모듈

13.1 쓰기

구문
import = "use" NAME [ "as" NAME ] ;

(1) 소스 하나는 모듈하나다. 호스트가 소스를 적재할 때 준 이름이 모듈의 이름이다(pnx 는 파일 이름에서 .pnx 를 뗀 것을 쓴다). 표준 모듈과 호스트 모듈(13.3)도 모듈이다.

(2) use 모듈 은 그 모듈을 이 소스에서 연다. 그 뒤로 모듈의 것은 경로모듈.이름 으로 쓴다. use 모듈 as 별명 은 같은 모듈을 별명.이름 으로 쓰게 한다. 맨 이름으로 쓰는 것은 핵 낱말과 이 소스가 선언한 것, 그리고 찾는 순서가 이름 붙인 모듈의 낱말(13.5)뿐이다.

(3) use 하는 모듈은 이미 있어야 한다: 표준 모듈, 호스트가 등록한 모듈, 또는 먼저 적재된 소스. pnx 는 use 이름 을 만나면 프로그램 파일 옆의 이름.pnx 를 먼저 적재한다.

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

출력

$ 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

출력

$ pnx 13-use-as.pnx
100
제약

(4) 없는 모듈을 use 하면 거절된다.

13-unknown-module.pnx

use geometrie

거절

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

(5) 모듈의 낱말을 맨 이름으로 쓰면 거절된다. 찾는 순서(13.5)가 그 모듈을 이름 붙였으면 그렇지 않다. 열지 않은 모듈의 경로도 거절된다.

13-bare-name.pnx

use geometry
200 50 area drop

거절

$ 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

거절

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

13.2 내보내기

(1) 다른 소스가 쓸 수 있는 것은 export 를 붙여 선언하거나 정의한 것뿐이다. 낱말, 상수, 전역은 모듈.이름 으로 쓰고(내보낸 전역에 넣을 때는 set 모듈.이름), 내보낸 record 와 type 과 표의 줄 타입은 이름만으로 쓴다.

(2) 아래 모듈 geometry 는 13.1 의 예가 쓴 것이다. square 는 내보내지 않았다.

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
제약

(3) 내보내지 않은 것을 쓰면 거절된다.

13-not-exported.pnx

use geometry
4 geometry.square drop

거절

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

13.3 표준 모듈과 호스트 모듈

(1) 표준 모듈(standard module)은 처리기에 들어 있는 언어의 일부다: str fmt hash encode bytes ptn rex json csv(16절). use 해야 보인다.

(2) 호스트 모듈(host module)은 호스트가 등록한 낱말의 묶음이다. 호스트가 등록하지 않은 모듈은 없다. 스크립트가 할 수 있는 바깥일(파일, 시계, 환경)은 호스트가 등록한 낱말이 전부다. pnx 는 표준 호스트 모듈 io file clock random env 를 등록한다(17절).

(3) err 는 use 없이 경로로 쓰는 상수의 묶음이다(11.1).

13.4 자료 적재

구문
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) 호스트가 자료 적재로 읽는 소스는 선언과 값만 받는다. 낱말 정의, 낱말 부르기, use, extern, test, 제어, 블록, cat 은 거절된다. 그래서 그런 소스는 아무 코드도 돌리지 못한다. 설정과 자료처럼 믿지 못하는 글을 읽을 때 쓴다.

(2) 값은 값 set 이름 으로, 칸은 값 번호 set 이름 으로("10.0.0.1" 0 set allow), 이름 붙은 줄의 필드는 값 줄 to
레코드.필드
로 넣는다. 코드와 같다(8.8, 9.4). 자료 적재의 소스가 선언한 것은 모두 내보낸 것으로 본다.

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;
}

출력

$ ./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
진단
조건메시지
없는 모듈no module of this name is registered or loaded
열지 않은 모듈이나 없는 레코드의 경로this path names neither a module in use nor a record
내보내지 않은 이름the module exports nothing of this name
자료 적재의 정의나 usea data source defines no words and uses no modules
자료 적재의 낱말 부르기a data source calls no words; only literals, const names and stores

13.5 찾는 순서

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

(1) search (io, str) 는 찾는 순서(search order)를 준다: 맨 이름을 찾아볼 모듈들이다. 이름 붙인 모듈은 use 처럼 열린다(13.1 (2), (3)). pnx 는 use 때처럼 프로그램 옆의 파일 모듈을 먼저 적재한다. search () 와 search none 은 순서를 비운다. 찾는 순서가 없으면 어느 모듈에서도 찾지 않는다.

(2) 코드의 맨 이름은 이 차례로 찾고, 처음 가진 것을 쓴다: 지역 변수와 매개변수, 이 소스(또는 세션)가 선언한 것, 핵 낱말, 그리고 찾는 순서의 모듈들을 왼쪽부터. 그래서 소스의 이름과 핵 낱말은 순서에 무엇이 있든 뜻이 바뀌지 않고, 순서에 더한 모듈이 전에 컴파일된 코드를 바꾸지 못한다. 핵 낱말과 이름이 같은 모듈의 낱말(len 곁의 str.len)은 경로로 쓴다. 경로는 전과 같이 읽는다.

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

출력

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

13-search-core.pnx

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

거절

$ 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) 찾는 순서는 소스나 세션 줄의 맨 위 수준에 필요한 만큼 쓸 수 있다. 하나하나가 그 자리부터 소스 끝까지의 순서를 바꾸고, 세션은 다음 순서가 나올 때까지 뒤 줄들에 그것을 지닌다. 낱말은 컴파일될 때 그 이름들이 찾은 것을 쓴다.

(4) 찾는 순서로 닿는 이름은 이름 가리기 규칙(9.5)에 들지 않는다: 지역 변수는 순서에 있는 모듈의 낱말과 같은 이름일 수 있고, 그 낱말 안에서는 지역 변수를 뜻한다.

제약

(5) 정의나 블록 안의 찾는 순서, 모듈을 두 번 이름 붙이거나 16 개보다 많이 이름 붙인 순서, 없는 모듈을 이름 붙인 순서는 거절된다.

진단
조건메시지
정의 안의 searchsearch stands at the top level, outside definitions and blocks
괄호가 없음search is followed by modules in parentheses: search (io, str)
모듈을 두 번this module is named twice in the search order
16 개보다 많음a search order names at most 16 modules