std 는 예약된 이름이고 프로그램이 아니라 컴파일러와 함께 있으므로 자기 루트를 갖는다 (--std=). 본문 없는 선언은 링커가 찾을 것 -- 런타임이나 C 라이브러리 -- 이므로 IR 에 extern 으로 나간다. 런타임에 write/alloc/free/exit 를 넣었다. 이것이 표준 라이브러리가 스스로 말할 수 없는 전부이고 나머지는 Ferro 로 쓴다. @trap @unreachable @size_of @align_of @line 을 내린다. 링크 이름에서 점과 괄호를 걸렀다. 유닛 경로에는 점이 있고 제네릭 인스턴스에는 괄호가 있는데 어셈블러가 받지 않는다.
64 lines
2.6 KiB
C
64 lines
2.6 KiB
C
#ifndef FE_RESOLVE_H
|
|
#define FE_RESOLVE_H
|
|
|
|
#include "ast.h"
|
|
#include "diag.h"
|
|
|
|
/* Unit-level resolution: identity, import bindings, and the unit graph.
|
|
This runs between parsing and semantic checking. It answers questions that
|
|
need more than one file -- what a unit is called, what it imports, and
|
|
whether those imports exist and terminate -- so that check.c can keep
|
|
looking at one function at a time. */
|
|
|
|
/* SPEC 8.1: each segment is ASCII lowercase, starts with a letter, continues
|
|
with letters, digits or '_', and is at most eight characters. The limit is
|
|
what makes a unit path map to a FAT/DOS 8.3 source path unambiguously. */
|
|
#define FE_UNIT_SEGMENT_MAX 8
|
|
#define FE_UNIT_PATH_MAX 128
|
|
#define FE_BUILD_UNIT_MAX 64
|
|
|
|
typedef struct FeUnit {
|
|
char name[FE_UNIT_PATH_MAX]; /* canonical dotted path */
|
|
char path[260]; /* source file it was read from */
|
|
FeAst ast;
|
|
char *source; /* owned; freed with the build */
|
|
unsigned long size;
|
|
int loaded;
|
|
int checked;
|
|
} FeUnit;
|
|
|
|
typedef struct FeBuild {
|
|
FeUnit units[FE_BUILD_UNIT_MAX];
|
|
unsigned count;
|
|
char root[260]; /* import root: where unit paths start */
|
|
/* Where `std.*` is looked for. The standard library is not under the
|
|
program's root -- it ships with the compiler. */
|
|
char std_root[260];
|
|
FeDiags *diags;
|
|
} FeBuild;
|
|
|
|
/* Validate the `unit` declaration against SPEC 8.1, and against the file it was
|
|
read from: the path must match the dotted name, so `game.world.map` has to
|
|
come from `game/world/map.fe`. `source_path` may be null to skip that half.
|
|
Returns non-zero when the unit is well formed. */
|
|
int fe_resolve_unit_identity(FeAst *ast, FeDiags *diags, const char *source_path);
|
|
|
|
/* Load `entry` and everything it imports, transitively.
|
|
|
|
The import root is derived from the entry file: a unit named `a.b` read from
|
|
`<root>/a/b.fe` fixes `<root>`, so a sibling `import c.d;` is looked for at
|
|
`<root>/c/d.fe`. Reports missing imports, import cycles, and binding
|
|
conflicts. Returns non-zero when the whole graph loaded cleanly. */
|
|
int fe_build_load(FeBuild *build, const char *entry, FeDiags *diags,
|
|
const char *std_root);
|
|
void fe_build_destroy(FeBuild *build);
|
|
|
|
/* The unit a binding refers to inside `unit`, or null.
|
|
The binding is the last segment of the import path unless `as` renamed it. */
|
|
FeUnit *fe_build_binding(FeBuild *build, FeUnit *unit, const char *binding);
|
|
|
|
/* The local name an import introduces: its alias, or the last path segment. */
|
|
const char *fe_import_binding(const FeNode *import);
|
|
|
|
#endif
|