feat(lang): friend module lab of fishing, data - a friend of the modules it names
A scoped friend sees those modules' private names and only the exports of every other; a plain friend module still sees everything. Reseed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
f4533331e7
commit
70d05bd504
8 changed files with 41388 additions and 41329 deletions
|
|
@ -103,7 +103,8 @@ visible.ludic:5: error: add is private to module bank; mark it 'export' where it
|
|||
A file in no module - the program's own file, the runtime - is public, and a package found
|
||||
through `ludic_modules` or the toolchain keeps its own module rather than its importer's. A
|
||||
program that says `friend module lab` sees every module's private names: that is for a test
|
||||
harness, which has to reach inside what it tests. `export` is a keyword before a declaration
|
||||
harness, which has to reach inside what it tests. `friend module lab of fishing, data` narrows
|
||||
that to the modules named: `lab` sees their private names, and every other module's exports only. `export` is a keyword before a declaration
|
||||
and is not the `@export` annotation, which names a C symbol.
|
||||
|
||||
To move an existing codebase onto modules, build it once with `LUDIC_VIS_REPORT=1`: every
|
||||
|
|
@ -132,7 +133,8 @@ fishing/land.ludic:4: error: fishing uses items.inv_add (items/index.ludic:3): a
|
|||
switched on one module at a time. Two module lines for one module add their lists together.
|
||||
- A file in no module (the program's root, the runtime) is unaffected either way, and a package's
|
||||
module (found through `ludic_modules` or the toolchain, such as `ludic_ui`) is always usable.
|
||||
- A friend of a module (below) is not held to its `uses` for that module.
|
||||
- A friend of a module (`friend module lab`, or `friend module lab of fishing`) is not held to its
|
||||
`uses` for that module.
|
||||
- The declared graph may not go round: `module a uses b` beside `module b uses a` is refused
|
||||
(`the modules' uses go round in a circle: a -> b -> a`) - one of them takes the other through a
|
||||
port instead.
|
||||
|
|
|
|||
5
changes/friend-of.md
Normal file
5
changes/friend-of.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
bump: minor
|
||||
type: feature
|
||||
**`friend module lab of fishing, data` - a friend of some modules, not all.** A scoped friend sees
|
||||
the private names of the modules it names and only the exports of every other; `friend module lab`
|
||||
alone still sees everything.
|
||||
12
examples/modules/friend_of.ludic
Normal file
12
examples/modules/friend_of.ludic
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# friend_of.ludic — L3: `friend module lab of bank` sees bank's private names and no other module's;
|
||||
# a test harness reaches inside exactly what it tests. `friend module lab` alone still sees all.
|
||||
#
|
||||
# Running it prints: 7 7
|
||||
import "bank"
|
||||
program FriendOf {
|
||||
friend module lab of bank
|
||||
entry {
|
||||
add(7)
|
||||
print(`{balance} {total()}`)
|
||||
}
|
||||
}
|
||||
10
examples/rejected/friend_scope.ludic
Normal file
10
examples/rejected/friend_scope.ludic
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# L3: a friend of kit is not a friend of bank - bank's private `add` stays out of reach
|
||||
import "private_bank"
|
||||
import "private_kit"
|
||||
program FriendScope {
|
||||
friend module lab of kit
|
||||
entry {
|
||||
add(5)
|
||||
print(total())
|
||||
}
|
||||
}
|
||||
|
|
@ -61,7 +61,11 @@ function mod_parse_friend() -> void {
|
|||
pi += 2
|
||||
let fm = eat_id()
|
||||
module_set(g_parse_file, fm)
|
||||
let scope = ""
|
||||
var scope = ""
|
||||
if is_id("of") {
|
||||
pi += 1
|
||||
scope = mod_parse_names()
|
||||
}
|
||||
push(g_mod_friends, fm)
|
||||
push(g_fr_scope, scope)
|
||||
}
|
||||
|
|
|
|||
41338
selfhost/ludicc.seed.ll
41338
selfhost/ludicc.seed.ll
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -738,6 +738,8 @@ function cmd_dev_test() -> int {
|
|||
feat_case("modules/uses", "", "8 3", "uses.ludic (L3: `module fishing uses base` - a module reaches only the modules it names)")
|
||||
reject_case("rejected/uses_missing", "fishing uses items.inv_add", "a module that says `uses` cannot reach a module it does not name, exported or not")
|
||||
reject_case("rejected/uses_cycle", "go round in a circle: a -> b -> a", "a cycle in the declared uses is refused")
|
||||
feat_case("modules/friend_of", "", "7 7", "friend_of.ludic (L3: `friend module lab of bank` sees bank's private names)")
|
||||
reject_case("rejected/friend_scope", "add is private to module bank", "a friend of one module is not a friend of another")
|
||||
vis_report_case("rejected/uses_missing", "uses: examples/rejected/uses_valley/items/index.ludic:3: items.inv_add used from", "LUDIC_VIS_REPORT=1 lists a uses violation and builds")
|
||||
feat_case("lang/checked", "", "7.5 3 12 hi 2 ok", "checked.ludic (L4: literals take their slot's kind, string(p), []string as []pointer, null, named args)")
|
||||
reject_case("rejected/wrong_arity", "this call to area leaves out h, which has no default", "a call with the wrong number of arguments is refused")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue