feat(lang): ports - port Clock { ... } in a module, bind Clock { ... } in the app

A port is a record of function values a module calls through
(Clock.now()) without naming the module that answers. A port used and
never bound, a bind missing a required member or naming one the port
lacks, and a second bind are refused; the binder must see the port, and
what it binds is checked from its own file. Reseed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-25 04:20:12 +03:00
parent d0ad364ad4
commit b1ccaf08bd
19 changed files with 50439 additions and 47750 deletions

View file

@ -0,0 +1,15 @@
# ports.ludic — L3 ports: module clock needs the time and declares `port Clock`; module app binds
# it with its own function; clock calls through `Clock.now()` and never names app. A member with a
# default (`day`) may be left out of the bind.
#
# Running it prints: 30 5
import "station/units"
import "station/clock"
import "station/app"
program Ports {
entry {
let a = Clock.now()
advance(-25)
print(`{a} {hour_of_day()}`)
}
}

View file

@ -0,0 +1,10 @@
# app/index.ludic - the app puts the program together: it sees the port and fills it
module app uses clock
bind Clock { now: fn game_hours }
var g_hours: int = 30
function game_hours() -> int {
return g_hours
}
export function advance(h: int) -> void {
g_hours += h
}

View file

@ -0,0 +1,13 @@
# clock/index.ludic - the clock needs the time of day and asks for it through a port: it names
# no module that answers, so it `uses` only units
module clock uses units
export port Clock {
now: fn() -> int
day: fn() -> int = fn first_day
}
function first_day() -> int {
return 1
}
export function hour_of_day() -> int {
return Clock.now() - (Clock.day() - 1) * HOURS
}

View file

@ -0,0 +1,3 @@
# units/index.ludic - a module with nothing to ask of anyone
module units
export const HOURS: int = 24