feat(lang): packages count under uses; a port of defaults may go unbound

A module that says uses must name every package module it reaches; a
package with no module line is named for its directory (ludic_render3d)
for this rule, so a mechanic reaching into the renderer is caught. Only
the engine's runtime needs no naming. 'module x uses' with nothing after
it reaches no other module. A port whose every member has a default
answers with its defaults when unbound, and 'new' of a port says to bind
it. ludic-dev test runs 'ludic test packages'. Reseed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-25 05:36:11 +03:00
parent e8c1d54a96
commit f4062010e9
15 changed files with 47465 additions and 46516 deletions

View file

@ -0,0 +1,11 @@
# L3: a port is not a record a program makes - it is filled once, by `bind`
program PortNew {
port Clock { now: fn() -> int }
function hours() -> int {
return 3
}
entry {
let c = new Clock
print(0)
}
}

View file

@ -0,0 +1,7 @@
# L3: a package's module counts under `uses` like any other - ludic_inventory is not named
import "uses_pkg_mech"
program UsesPackage {
entry {
print(stock())
}
}

View file

@ -0,0 +1,8 @@
# uses_pkg_mech/index.ludic - a mechanic that says it uses ludic_base, then reaches into another
# mechanic package
module mech uses ludic_base
import "ludic.base"
import "ludic.inventory"
export function stock() -> int {
return inv_count(0)
}

View file

@ -0,0 +1,7 @@
# uses_r3d_mech/index.ludic - a mechanic that reaches into the renderer, which has no module line
module mech uses ludic_base
numbers float
import "ludic.render3d/fmath.ludic"
export function circle() -> float {
return PI * 2.0
}

View file

@ -0,0 +1,8 @@
# L3: a package with no module line is still named under `uses` - ludic_render3d is not
import "uses_r3d_mech"
program UsesRender3d {
numbers float
entry {
print(circle())
}
}