diff --git a/docs/packages.md b/docs/packages.md index b330e5a..730dacb 100644 --- a/docs/packages.md +++ b/docs/packages.md @@ -81,29 +81,39 @@ installs; the next install records the hashes. `pkg list` output is unchanged. Each dependency lands in `flint_modules//` with its sources and -its own `flint.toml`: +its own `flint.toml`. A package can expose its default module as +`main.fl`, as a same-named file such as `levenshtein/levenshtein.fl`, +or as a flat `flint_modules/.fl` file. ```text flint_modules/ libfoo/ flint.toml - foo.fl + main.fl + levenshtein/ + flint.toml + levenshtein.fl ``` ## imports and resolution ```flint -import "libfoo/foo.fl" -print(foo.hello()) +import libfoo +print(libfoo.hello()) + +import levenshtein +print(levenshtein.distance("kitten", "sitting")) import "gitlib/g.fl" print(g.greet()) ``` -A quoted path with a `/` or a `.fl` extension is a file: relative to the -importing file, except `flint_modules/` is also searched, and packages -resolve before the standard library. A bare name (`import math`) is the -standard library. +A bare name first checks installed packages in `flint_modules/`: +`/main.fl`, then `/.fl`, then the flat +`.fl` layout. If no package matches, the standard library is +checked (so `import math` still imports the library). A quoted path with +a `/` or a `.fl` extension can address a file relative to the importing +file; package-internal paths are also resolved from `flint_modules/`. ## transitive dependencies diff --git a/rust/flintlang/c-src/src/runtime/sys.c b/rust/flintlang/c-src/src/runtime/sys.c index 67de00b..9e26a09 100644 --- a/rust/flintlang/c-src/src/runtime/sys.c +++ b/rust/flintlang/c-src/src/runtime/sys.c @@ -482,6 +482,21 @@ char *sys_resolve_module(const char *path) main_file); free(main_file); } + /* + * Also support a single-file package named after + * itself, e.g. levenshtein/levenshtein.fl. + */ + if (found == NULL) { + size_t need_named = strlen(dir_main) + 1 + + pathlen + 3 + 1; + char *named = malloc(need_named); + if (named != NULL) { + snprintf(named, need_named, "%s/%s.fl", + dir_main, path); + found = pkg_candidate(named); + free(named); + } + } if (found == NULL) { size_t need2 = strlen(dir_main) + 4; diff --git a/src/runtime/sys.c b/src/runtime/sys.c index 67de00b..9e26a09 100644 --- a/src/runtime/sys.c +++ b/src/runtime/sys.c @@ -482,6 +482,21 @@ char *sys_resolve_module(const char *path) main_file); free(main_file); } + /* + * Also support a single-file package named after + * itself, e.g. levenshtein/levenshtein.fl. + */ + if (found == NULL) { + size_t need_named = strlen(dir_main) + 1 + + pathlen + 3 + 1; + char *named = malloc(need_named); + if (named != NULL) { + snprintf(named, need_named, "%s/%s.fl", + dir_main, path); + found = pkg_candidate(named); + free(named); + } + } if (found == NULL) { size_t need2 = strlen(dir_main) + 4; diff --git a/tests/pkg_test.sh b/tests/pkg_test.sh index 7d1d2d6..e0e99c4 100644 --- a/tests/pkg_test.sh +++ b/tests/pkg_test.sh @@ -123,7 +123,7 @@ cat > "$WORK/gitsrc/flint.toml" <<'EOF' name = "shout" version = "0.3.0" EOF -cat > "$WORK/gitsrc/main.fl" <<'EOF' +cat > "$WORK/gitsrc/shout.fl" <<'EOF' export fn loud(who) { return "HEY " + who } @@ -158,7 +158,7 @@ expect "git import works" "HEY zed" "$("$FLINT" use.fl 2>&1)" pin=$(sed -n '/^commit = /s/commit = "\(.*\)"/\1/p' flint.lock) expect "lock pins a 40-char commit" "40" "${#pin}" -cat > "$WORK/gitsrc/main.fl" <<'EOF' +cat > "$WORK/gitsrc/shout.fl" <<'EOF' export fn loud(who) { return "LOUDER " + who }